I am currently building an angular 7 application. In this application I am trying to integrate the auth0 authentication.
I am using the following version: “@auth0/auth0-spa-js”: “^1.1.0”
I managed to login and logout, with no issues. Now my angular application will call some lambda functions that I own, and this lambda function will verify if the access token is jwt format.
So from the angular application I am trying to find a way to get this id_token to send it in the header: Bearer id_token, but I can’t seem to find how to get this token.
I am creating the the auth client using : createAuth0Client
In the new auth0-spa-js, the raw ID token isn’t available but only the decoded ID token payload.
There was a discussion around it before, and the conclusion was that such method would currently not be provided unless enough valid use cases exist:
So, to answer the question as per status quo: it’s currently not available in the new auth0-spa-js but only in the old auth0-js.
will verify if the access token is jwt format
But to clarify this part, is it only verifying the correct format, or also the valid signature, issuer, audience, expiration date, etc.?
Referring to:
And what are you doing with that ID token in the lambda function, except verifying it? How are you using it or it’s payload there (from a business logic perspective)?
By the way: this blog article might also be of interest about the launch of the new Auth0 SPA SDK.
In the link you suggested ‘Validate ID Tokens’, the verification is done on the id_token (jwt format), the access_token I have, is not JWT, this is why I need the id_token, so I can validate it.
Following is a part of the lambda function that verifies the jwt:
const jwt = require('jsonwebtoken');
const verifyJWTToken = (jwtToken, pubKey) => {
return new Promise((resolve, reject) => {
jwt.verify(jwtToken, pubKey, { algorithms: ['RS256'] }, (err, decoded) => {
if (err) {
reject(err);
} else {
resolve(decoded);
}
});
});
};
const handler = (event, context, callback) => {
// The authorization token is in the form of "Authentication": "Bearer (some ID token from the frontent)"
if (!event.authorizationToken) {
callback('Could not find authToken');
return;
}
const jwtToken = event.authorizationToken.split(' ')[1];
if (!jwtToken) {
callback('Could not find authToken');
return;
}
const decodedToken = jwt.decode(jwtToken, {complete: true});
const Auth0ApiBaseUrl = process.env.AUTH0_DOMAIN;
if(!Auth0ApiBaseUrl) {
callback('Base Url not found');
return;
}
return rp(`https://${Auth0ApiBaseUrl}/.well-known/jwks.json`)
.then((jwks) => {
const jwksKey = JSON.parse(jwks).keys[0];
//Validate the algorithm
if (!jwksKey) {
throw new Error('No supported jwt keys');
}
//Validate the algorithm
if (jwksKey.alg !== 'RS256' || decodedToken.header.alg !== 'RS256') {
throw new Error('Invalid algorithm used, only RS256 supported');
}
//Validate the signing key
if (!jwksKey.kid || decodedToken.header.kid !== jwksKey.kid) {
throw new Error('Invalid signing algorithm');
}
//Validate the certificate
if (!jwksKey.x5c[0]) {
throw new Error('No certificate found');
}
const cert = `-----BEGIN CERTIFICATE-----\n${jwksKey.x5c[0]}\n-----END CERTIFICATE-----\n`;
return cert;
})
.then((pubKey) => verifyJWTToken(jwtToken, pubKey))
.then(() => {
// now that the access token is valid I can access some secret functionalities
})
.catch((err) => {
console.log('Failed jwt verification: ', err, 'auth: ', event.authorizationToken);
callback('Authorization Failed');
});
};
Please let me know if i’m missing something, or if I need to validate the token in another way.
The token is already verified by the auth0-spa-js, so you don’t need to additionally do it.
Are you using the ID Token elsewhere other than in your Angular client application? I mean, is there any plan to pass the ID Token to the server side in order to use it’s payload there? Did you setup the lambda just for the token verification and nothing else?
@mathiasconradt yes this lambda function will only validate the token, if it’s valid it will let the call go through to another lambda function that will do its job. So the first lambda function is a custom authoriser that sit on top of API GATEWAY, to verify the request coming from the frontend.
Here’s an example:
So, I have a frontend that will call a getUserList , in AWS api gateway, there is a get endpoint to get the list of user from an s3 or a database, before calling the s3 or the database, I call this lambda (custom authoriser) to check if the token is valid, if so, I continue to flow to retrieve the list of users, if not, I return an error to the frontend saying that the token is not valid.
For this, you should use the access token, not the ID token. ID token is not meant to be used for authorization (protecting a resource server, such as your API/backend), that’s what an access token is for. And that one you can already get from the SDK as you noted already.
Related:
So, usually in such scenario: you would register your API in Auth0 under Dashboard > API, create permissions/scopes for the API such as read:users for example, and then request this scope when you make the authorize call in your client application, and also add your API identifier as audience parameter such as:
scope: 'openid profile email read:users', // note the added scope at the end
audience: 'https://your-api/'
So, your backend or lambda should validate the access token, not the ID token, and use that instead as well.
Update: The raw id token is now available via this method:
$('#getIdTokenClaims').click(async () => {
const claims = await auth0.getIdTokenClaims();
// if you need the raw id_token, you can access it
// using the __raw property
const id_token = claims.__raw;
});