I'm trying to figure out how to do the identity server 4 authentication below using NodeJS - way out of my comfort zone here.
services.AddAuthentication(IdentityServerAuthenticationDefaults
.AuthenticationScheme)
.AddIdentityServerAuthentication(
options =>
{
options.Authority = "<authority-url>";
options.ApiName = "<api-url>";
});
I'm missing something in the flow here as the C# implementation isn't provided a secret or similar - so the token is probably verified via identity server? How would I verify the token using NodeJS if I don't have a 'secret' to verify it with?
I've stumbled on introspection endpoint - am I heading in the right direction?
I was able to solve this using the jwks -endpoint and it's public keys to verify tokens and then I also found a nice package that I used to prepare the middleware:
private issuer: string = process.env.idsrv;
auth = jwt({
secret: jwksClient.expressJwtSecret({
cache: true, // see https://github.com/auth0/node-jwks-rsa#caching,
cacheMaxAge: ms('24h'),
rateLimit: true, // see https://github.com/auth0/node-jwks-rsa#rate-limiting
jwksRequestsPerMinute: 100,
jwksUri: `${this.issuer}/.well-known/jwks`
}),
// validate the audience & issuer from received token vs JWKS endpoint
audience: `${this.issuer}/resources`,
issuer: this.issuer,
algorithms: ["RS256"]
});
The accepted question is right. but i wanted to fix some of it's trial errors.
you can easily (it took me 4 days) add authentication to your express api with ids4.
it's how its work:
creating a middleware:
const jwt = require("express-jwt"),
jwksClient = require("jwks-rsa");
const auth = jwt({
secret: jwksClient.expressJwtSecret({
cache: true, // see https://github.com/auth0/node-jwks-rsa#caching
rateLimit: true, // see https://github.com/auth0/node-jwks-rsa#rate-limiting
jwksRequestsPerMinute: 2,
jwksUri: `${issuer}/.well-known/openid-configuration/jwks`,
}),
audience: "api1.resource", // <---- its your api resource.
issuer: issuer, // <----- address of identityserver4.
algorithms: ["RS256"], //<----- its needed algorithm to handle secret.
});
The following auth middleware is like following code in .net:
services.AddAuthentication(IdentityServerAuthenticationDefaults
.AuthenticationScheme)
.AddIdentityServerAuthentication(
options =>
{
options.Authority = "<authority-url>";
options.ApiName = "<api-url>";
});
to secure a nodejs route you can use following example:
// this is the secured route by identityserver4
// the jwt module set the ids4 auth result in req.user object
// so you can use it to access logged in user claims and stuff.
// for example testing with client credentials it return some info about the jwt token sent to the /me endpoint.
app.get("/me", auth, (req, res) => {
const user = req.user;
debug("req.user: %O", user);
return res.json(user);
});
// this a unsecured route. so anyone can call this route without any restrictions.
app.get("/", (req, res) => {
return res.send("Hello");
});
It takes me so long to find how to secure nodejs or express with identityserver4 but it was as simple as it look like.
The code here is from the following identityserver4 community example with full ids4 and node api and javascript client and .net console client:
https://github.com/lyphtec/idsvr4-node-jwks
There is a good documentation about this example in its own github repository too.
You can download the node api and run it with yarn start or npm run start.
I tested it with client credentials flow and it worked like a charm.
Wish all of you luck.
If you want only to validate your token you can use the following package:
npm install token-introspection --save
This package is configured with endpoint and client credentials, and a function is returned.
Calling that function with token, and optional token_type_hint will return a Promise.
const tokenIntrospection = require('token-introspection')({
endpoint: 'https://example.com/introspect',
client_id: '<Client ID>',
client_secret: '<Client Secret>',
});
tokenIntrospection(token).then(console.log).catch(console.warn);
Example :
Here is a middleware to validate the token :
module.exports = (req, res, next) => {
const token = "wEvxS0y2TkvCjLpKP33oGTK0BcKUb6MHt1u3AeMu8h4"; // get your token from your request
const tokenIntrospection = require('token-introspection')({
endpoint: 'http://localhost:5000/connect/introspect',
client_id: 'api1',
client_secret: 'apisecret',
});
tokenIntrospection(token).then(result => {
console.log(result);
next();
}).catch(console.warn);
}
then you can use it as below :
const auth = require('./atuh')
app.get('/', auth, (req, res, next) => {
res.send("Hi");
})
Related
My goal is to create an authentication backend and I would like to implement google's Oauth2, and for that I decided to follow the passport documentation. My only issue is, how can I test this on my Postman? I'm just developing a backend and I don't know if it's working, I know it sounds a little silly but for a beginner like me it's a lot. Thanks
const dotenv = require('dotenv').config();
const express = require('express');
const passport = require('passport');
var GoogleStrategy = require('passport-google-oauth20').Strategy;
const app = express();
const port = process.env.PORT;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "http://www.example.com/auth/google/callback"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] }));
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
try {
app.listen(port);
console.log(`Server starting on port ${port}`);
} catch (err) {
console.log(err);
}
Whichever OAuth2 service is pretty simply, if you step into it ;)
In first step you send client_id and client_secret to authorization uri.
In second step, the user authenticates with his credentials and you receive the code which you exchange with authorization server for token.
You make request with Bearer token.
Postman can handle some of the things for you. So:
In Google Dev Console create your credentials.
As callback uri fill in:
https://www.getpostman.com/oauth2/callback
https://oauth.pstmn.io/v1/callback
In Postman create new Collection and define following variables:
Define following Authorization:
When you click Get New Access Token you will be asked to login to Google and get back with token.
With this token you can use whichever service you have in scope and your project on Developer Console includes (look for Enabled APIs and services).
Example request:
Create new GET request and save it in your collection, so the variables and tokens are inherited.
URL is: https://www.googleapis.com/oauth2/v1/userinfo?alt=json
Auth in Postman: Inherit auth from parent.
And Send...
Took me months to understand, so hope you'll be swifter :)
I'm very new to web development, and am trying to implement authorization through a 3rd party for my app. Since I'm testing, the app as well as the server are both hosted locally. I have Oauth2.0 set up to authorize with github so that when I access the server (port 2), it asks for github auth then redirects to the app on port 1 with a code (the token is still null). However, if I go directly to the app hosted on port 1, I do not need to authenticate and there is no code given. Ideally, when the user goes to the app URL, they are redirected to github authentication, then back to the app.
I do not need to use the github API, I only want to use the github account login to authenticate and access the app.
API/server: localhost:3002
App: localhost:3001
const clientId = '...'
const clientSecret = '...'
const redirectUri = 'localhost:3001'
app.get('/', (req, res) => {
console.log('authorizing client through github...')
res.redirect(`https://github.com/login/oauth/authorize?client_id=${clientId}`);
});
...
const axios = require('axios');
let token = null;
app.get('/oauth-callback', (req, res) => {
const body = {
client_id: clientId,
client_secret: clientSecret,
redirect_uri: redirectUri,
code: req.query.code
};
const opts = { headers: { accept: 'application/json' } };
axios.post(`https://github.com/login/oauth/access_token`, body, opts).
then(res => res.data['access_token']).
then(_token => {
console.log('My token:', token);
token = _token;
res.json({ ok: 1 });
}).
catch(err => res.status(500).json({ message: err.message }));
});
Apologies if this is a simple question, the Oauth docs aren't very helpful.
I'm new to NodeJS and developing an API using it,
I want the API to be authenticated with an API token method (only people with a token stored in DB, created through a specific encryption should be able to access the API resource.)
I'm using an SQL server, NodeJS, and the Express framework.
Please guide me in what I should use to authenticate the API request.
Thanks in advance.
You could use passport.js with JwtStrategy. This is the idea:
mypassport.js
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'yourSecret'
};
passport.use(new JwtStrategy(opts, (payload, done) => {
const user = findUserById(payload.id);
if (!user) {
return done('user not exists', null);
}
return done(null, user);
}));
server.js (using express)
require('./mypassport'); // <- initialize passport strategies
//you could also use passport with local strategy for this
app.post('login', (req, res) => {
const username = req.query.username;
const password = req.query.password;
if (validLogin(username, password)) {
const user = findUserByUsername(username);
const jwt = createTokenWithSecret(user, 'yourSecret'); // You can use jwt-simple for this
res.json({ token: jwt });
} else {
//send unauthorized
}
});
const requireLogin = passport.authenticate('jwt');
app.get('/something', requireLogin, (req, res) => {
//here, user is authenticated and available in 'req.user'
});
First, you must login with POST /login { username: 'john', password: '1234' }. That will return a JSON with the jwt token like this:
{ token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' }
In subsequent requests, you must send a header Authorization with value: Bearer {token} so passportjs and JwtStrategy can authorize the request.
Hope it helps!
NOTE: I have not tested code above, it just shows the approach.
For API Authenication use Passport JS
You can use json web token (jwt) for API authorization. There are node modules available which provides authentication functionality and you can simply use.
Please have a look at this article: https://medium.freecodecamp.org/securing-node-js-restful-apis-with-json-web-tokens-9f811a92bb52?gi=89f3f4d89dfd
Right now I believe I have most things setup correctly. Auth0 is saving the jwt to the client who is then using it for future requests. I use express-jwt to verify the token. From reading the Auth0 docs, I think I need the client secret (when I use that to decode the jwt I get an odd error: UnauthorizedError: error:0906D06C:PEM routines:PEM_read_bio:no start line) So I'm just wondering where about's this secret key comes from?
Thanks
Current code which just decodes the JWT into its signing scheme etc:
const jwtCheck = jwt({
secret: jwks.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: 'https://xelitexirish.eu.auth0.com/.well-known/jwks.json'
}),
audience: 'https://www.shaunoneill.com',
issuer: 'https://xelitexirish.eu.auth0.com/',
algorithms: ['RS256']
});
Based on comment from OP, to read the values of the body of JWT, simply base64 decode it. You can use a library for this, eg jwt-decode for nodejs.
See example usage below (taken from README for lib):
var jwtDecode = require('jwt-decode');
var token = 'eyJ0eXAiO.../// jwt token';
var decoded = jwtDecode(token);
console.log(decoded);
/* prints:
* { foo: "bar",
* exp: 1393286893,
* iat: 1393268893 }
*/
The claims that will be in your Token (here, referring to ID Token) are dependent on what scope you provided when you authenticated. For instance, if you use scope: openid profile email you will get everything returned inside your ID Token.
Here, assumed the JWT was verified using library, and now you have the JWT you'd like to read some if its claims from the body.
If you are using express-jwt middleware then payload is by default saved in request object and you can access it like this request.user
Example for an endpoint:
//jwtMiddleware is express-jwt middleware
app.get('/', jwtMiddleware, function (req, res) {
console.log(req.user);
res.send('hello world');
});
Auth0 documentation describes how to set up express-jwt middleware to protect endpoints. The trouble is that the documentation doesn't seem to cover how you get a valid JWT in the first place.
On the angular side, there's documentation on using angular plugins to implement a login page, that's fine. How would one implement a route using express that would take a username/password and return to the client the appropriate JWT such that subsequent requests would be authorized?
I think I may be missing a basic concept about JWT here; via Auth0, when using Username-Password-Authentication, my guess is that Auth0 acts as the repo for those credentials. There's documentation out there about wiring passport to auth0 and JWT, the problem with those is that this documentation assumes that the username/password database is some MongoDB instance locally...I want to avoid that type of setup which was an initial attraction with auth0.
Are there sample projects that cover this, showing how to get a valid JWT on a back-end, without some separate front-end angular app requesting it first?
I use passport.js built in local strategy for authentication and store user information in a JWT that I read on routes that require authorization.
User id's can be serialized/deserialized into and out of the express sessionto obtain the user identifier using the auth token (JWT) in the request. This is in my opinion the best approach since it limits the amount of data stored on the client and provides better security than storing any user information. Here's an example of this in express:
//Set a session secret
var secrets = { sessionSecret: process.env.secret || 'my secret string'};
//Require express-jwt and set a secret for the cookie
var expressJwt = require('express-jwt');
var validateJwt = expressJwt({ secret: secrets.sessionSecret });
//Returns a jwt token signed by the app secret
var signToken = function(id) {
return jwt.sign({
id: id
}, secrets.sessionSecret, {
expiresInMinutes: 60 * 24 // 24 hours
});
};
//Set token cookie directly
var setTokenCookie = function(req, res) {
if (!req.user) {
return res.status(404).json({
message: 'Error during user validation'
});
}
var token = signToken(req.user.id, req.user.role);
res.cookie('token', JSON.stringify(token));
};
//Check to see if user is authenticated (call this when a route is requested)
var isAuthenticated = function(req, res, next) {
// allow access_token to be passed through query parameter as well
if (req.body && req.body.hasOwnProperty('access_token')) {
req.headers.authorization = 'Bearer ' + req.body.access_token;
}
// Validate jwt token
return validateJwt(req, res, next);
};
You can use these methods as middleware in express. Say the above code was token.js, you can force it to execute on each request to a route like this:
app.get('/employee', token.isAuthenticated, employeeController.getEmployees);
I haven't worked with angular but it works great on the backbone projects i've worked on and this process should work with any browser based client that can supply a X-auth cookie on each request. You can do this by using the ajax setup:
$(document).ajaxSend(function(event, request) {
var token = readCookie('token');
if (token) {
request.setRequestHeader('authorization', 'Bearer ' + token);
}
});
Here is an example of middleware that validates a users login and returns a token to the client that can be used on subsequent requests:
var validateLogin = function (req, res, next) {
var username = req.params.username;
// Authenticate using local strategy
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(404).json({
info: [{
msg: info.message
}]
});
}
// Send user and authentication token
var token = token.signToken(user.id, user.role);
res.cookie('token', token);
res.render('index', {token: token, user: user});
})(req, res, next);
};
#FrobberOfBits
This is to answer the follow-up Q posted by FrobberOfBits on Feb 6, 2016 at 3:04
I use auth0 for local + social media authentication.
The way auth0 works is, you hand over the approach to authenticate to auth0 ...either it be local with db or social media.
It is a bundled approach where local db and social media authentication is all bundled and provided as a service to you by auth0.
Hope this helps.