How to include acr_values in Passport authenticate - node.js

I have Passport set up and working using an oauth2 strategy (code flow) against Identity Server 4. I need to include acr_values in the call to the Identity Server (this is working from another client correctly).
My understanding (as shown here for example) is that the following code should add acr_values to the auth call:
app.get('/auth', (req, res, next) => {
passport.authenticate('oidc', { acr_values: 'urn:grn:authn:fi:all' })(req, res, next);
});
But this doesn't work. Running the code from that sample also doesn't work.
Is this something I'm doing wrong, or has it changed?
How can I have passport include acr_values in the call to the Identity Server?

The acr_values format you use is not valid, it must be a single string which is space separated like: acr_1 acr_2 tenant:tenant_value idp:idp_value
Per Docs:
acr_values
allows passing in additional authentication related information - identityserver special cases the following proprietary acr_values:
idp:name_of_idp bypasses the login/home realm screen and forwards the user directly to the selected identity provider (if allowed per client configuration)
tenant:name_of_tenant can be used to pass a tenant name to the login UI
Here is where in code it gets validated: https://github.com/IdentityServer/IdentityServer4/blob/main/src/IdentityServer4/src/Validation/Default/AuthorizeRequestValidator.cs#L771
Example in tests: https://github.com/IdentityServer/IdentityServer4/blob/main/src/IdentityServer4/test/IdentityServer.IntegrationTests/Endpoints/Authorize/JwtRequestAuthorizeTests.cs#L667

Related

how to verify a firebase admin on backend

I'm trying to implement middleware in an express server that sets custom uid/admin headers on the incoming request. This modified request will then be used after the middleware to see if an authenticated user/admin is accessing that particular resource.
To do this for a client, I just grab the token on the Authorization header and feed it into the firebase admin api's verifyIdToken method. If a uid exists, I set the header. For example:
app.use((req, res, next) => {
/* get rid of headers sent in by malicious users. */
delete req.headers._uid;
try {
const token = req.headers.authorization.split(' ')[1];
_dps.fb_admin.auth().verifyIdToken(token).then(claims => {
if (claims.uid) { req.headers._uid = claims.uid; }
next();
}).catch(err => next());
} catch(err) { next(); }
});
Two questions:
1) As an admin with a service account on another server, how would I send a request to this server such that this server can determine an admin sent the request?
2) How would I identify the admin on this server?
You will need to create your own custom Firebase token to include custom fields such as isAdmin: true in the JWT. See https://firebase.google.com/docs/auth/admin/create-custom-tokens
See (1)
Use the setCustomUserClaims() API to add a special "admin" claim to all admin user accounts, and check for it when verifying ID tokens. You can find a discussion and a demo of this use case here (jump ahead to the 6:45 mark of the recording).
Perhaps a solution would be to simply generate an API key of decent length and set it as an environment variable on each of my servers. I could then send this in the Authorization header whenever i want to make an admin https request and verify it in the middleware of the receiver by doing a simple string compare. The only people that could see this API key are those that have access to my servers (AKA admins). Let me know if something is wrong with this approach. It sure seems simple.

GCP Consume a REST API after OAuth in Node.js

I am working to implement a Node.js webapp to be deployed on GCP App Engine.
Following the Node.js Bookshelf App sample, I did manage to implement a basic user authentication flow using the passport-google-oauth20 and retrieve basic profile information. I basically just got rid of what was not needed for my purposes
My custom code is available at: gist.github.com/vdenotaris/3a6dcd713e4c3ee3a973aa00cf0a45b0.
However, I would now like to consume a GCP Cloud Storage API to retrieve all the storage objects within a given buckets with the logged identity.
This should be possible by:
adding a proper scope for the request.
authenticating the REST requests using the user session token obtained via OAuth.
About the post-auth handler, the documentation says:
After you obtain credentials, you can store information about the
user. Passport.js automatically serializes the user to the session.
After the user’s information is in the session, you can make a couple
of middleware functions to make it easier to work with authentication.
// Middleware that requires the user to be logged in. If the user is not logged
// in, it will redirect the user to authorize the application and then return
// them to the original URL they requested.
function authRequired (req, res, next) {
if (!req.user) {
req.session.oauth2return = req.originalUrl;
return res.redirect('/auth/login');
}
next();
}
// Middleware that exposes the user's profile as well as login/logout URLs to
// any templates. These are available as `profile`, `login`, and `logout`.
function addTemplateVariables (req, res, next) {
res.locals.profile = req.user;
res.locals.login = `/auth/login?return=${encodeURIComponent(req.originalUrl)}`;
res.locals.logout = `/auth/logout?return=${encodeURIComponent(req.originalUrl)}`;
next();
}
But I do not see where the token is stored, how can I retrieve it and how to use it to consume a web-service (in my case, GCP storage).
I am not at all a node.js expert, so it would be nice having a bit more clarity on that: could someone explain me how to proceed in consuming a REST API using the logged user credentials (thus IAM/ACL privileges)?
If you want to access Cloud Storage through the use of a token obtained with OAuth, when the application requires user data, it will prompt a consent screen, asking for the user to authorize the app to get some of their data. If the user approves, an access token is generated, which can be attached to the user's request. This is better explained here.
If you plan to run your application in Google App Engine, there will be a service account prepared with the necessary authentication information, so no further setup is required. You may need to generate the service account credentials (generally in JSON format), that have to be added to the GOOGLE_APPLICATION_CREDENTIALS environment variable in gcloud.
Here is an example of how to authenticate and consume a REST API with the token that was obtained in the previous step. This, for example, would be a request to list objects stored in a bucket:
GET /storage/v1/b/example-bucket/o HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer [YOUR_TOKEN]

PassportJS + RestAPI +SPA

I am using ExpressJS to build RestAPI, client is SPA and support authenticate by Google/FaceBook/GitHub/... via PassportJS. My question, callback from social login will return to RestAPI or SPA? If system returns to RestAPI, how can to redirect to home page on SPA. Another case, if system callback SPA, how can RestAPI receive and validate token from client. Please let me know common approachs.
Thanks,
You provide the callback url to the authentication service, you decide whether you handle the route by the SPA or the API. Oauth authentication (simplified) has two steps. Illustration on github:
Step 1) https://github.com/login/oauth/authorize?client_id=*YOUR_CLIENT_ID*$redirect_uri=*YOUR_REDIRECT_URI*
Opens a popup dialog that requests the user to authorize your application, if successful returns to your redirect_uri with a query parameter ?code=AUTHORIZATION_CODE
Step 2)You exchange the above AUTHORIZATION_CODE for a long-term access token via https://github.com/login/oauth/access_token
In your architecture, you should do Step 1 in the SPA and Step 2 in the rest api. You should rely on the spa to get the authorization code from the authentication provider, send that to your rest api, let the rest api exchange for a long term access token, save that token to the database, use it to retrieve user information or do whatever you want with it, then log in the user.
For step 1, you only need the CLIENT_ID, for step 2 CLIENT_ID and CLIENT_SECRET as well, so you can keep your application secure by storing the CLIENT_SECRET on the server side only.
The problem with having the callback uri handled by your rest api, is that the callback uri is called by the authentication provider (in this case github) and not by your SPA, therefore you can't send a response that redirects the user to the homepage. This would only work if your templates and routing were handled on the server side, which I assume is not the case in your architecture.
It's not obvious from the documentation, but when you register a passport middleware on a route like app.post('/login',
passport.authenticate('github'),, the middleware will check if the 'code' query param contains an AUTHORIZATION_CODE, if not, it kicks off step 1, if yes step2.
I used same stack(express, angular, passport) and followed that approach.
I created a button.
Login with facebook
Also I have two routes for passport
// send to facebook to do the authentication
app.get('/auth/facebook', passport.authenticate('facebook', {scope: 'email'}));
// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback', passport.authenticate('facebook', {
successRedirect: '/#/profile',
failureRedirect: '/' //Redirect Homepage
}));
This code shows that if you login successfully you will be redirect to angular route(/#/profile) After redirect you'll have a cookie which has a token with name connect.sid since passportjs uses express-session.
Then you can check if user logged in everywhere by this middleware
// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect(301, '/');
}
You can take a look at my repository which contains the code above.
https://github.com/AOnurOzcan/meanTest
If you encounter a problem please let me know.

NodeJS OAuth2.0 principles

Recently I was working on a nodeJS project and I was thinking how to go about and implement the security module of my mobile application. I had a previous experience from OAuth 2.0 protocol which I used in C# projects in the past.
In .NET there are two nice open source project
https://github.com/thinktecture/Thinktecture.IdentityServer.v3
https://github.com/thinktecture/Thinktecture.AuthorizationServer
The former is an Identity Provider supporting federated authentication and the later is an OAuth 2.0 provider.
So I decided to employ the same security infrastructure for my nodeJS app. But as far as I know, there is nothing equivalent to those projects.
I found some really nice project, which are not yet complete but are a good start:
https://www.npmjs.org/package/node-oauth2-server
https://github.com/domenic/restify-oauth2
In addition, I came across a nice article that suggests a nice way to deal with authentication in nodeJS. https://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/ and a similar answer to a questtion on stackoverflow. Auth between a website and self-owned API
From what I understood, expressJwt guards our api's and basically will validate the access token sent by the user. But I'd like to go a step further, and associate a token with app specific scopes, in a similar way that one would do with the OAuth2.0 protocol. So for example, I would like to assign a write, read etc. scopes and have expressJwt check if the user's token has the required scopes to access as specific API endpoint.
I would be grateful if you could provide me with some suggestions about how to deal with this topic.
First, you need to generate a token with such claims. This could be in an API or some other place:
var jwt = require('jsonwebtoken');
var claims = {
name: user.name
can_write: true,
can_post_timeline: false
};
var token = jwt.sign(claims, 'my-super-secret');
Then, to validate you will do something like this:
var jwt = require('express-jwt');
app.use(jwt({secret: 'my-super-secret'}));
function require_time_line_access (req, res, next) {
if (!req.user.can_post_timeline) return res.send(401);
next();
}
app.post('/timeline',
require_time_line_access,
function(req, res) {
//do timeline stuff
});
express-jwt validates the signature of the token, expiration and few other things. If everything is okay it puts the decoded token in req.user, and if is not okay it returns 401.
require_time_line_access is a middleware that ensure the user has this claim, if it doesnt it returns 401. You can put this middleware in every endpoint that needs this claim.

Web application authentication strategies

I'm looking for some advice with authentication for my web app. I'm using Node, Express and Passport to build out this app
The app has a REST API using Basic Auth (no session creation), and hosts several Angular.js web pages using form Auth (with session creation).
I would like the Angular pages to connect to the REST API, which is using a different Auth strategy. It seems I have two options:
Create a custom Basic Auth middleware, (because Passport doesn't do this out of the box). This will do session Auth if request has one, otherwise standard Basic Auth
Expose two API's one with Basic Auth (for external use) and one with form Auth (for the app pages)
If also heard that using OAuth2 might be an option, but surely that only makes sense for authenticating with a third party?
My current solution has been to perform mixed auth (session and basic) on the rest api. If a session exist continue, otherwise perform basic auth. As follows:
api.coffee:
app.api.external.get("/agents", [auth.basic], (req, res) ->
res.json myListOfAgents
auth_middleware.coffee
basic: (req, res, next) ->
if req.isAuthenticated()
return next()
else
return passport.authenticate('basic', { session: false })(req, res, next)

Resources