How would one access the JWT id_token response type from Auth0?
What are you trying to do
Currently using Hasura and am trying to use Auth0 as my auth. However in this tutorial it requires a SPA vs a Regular Web App. And honestly I'm unfamiliar with https://hasura.io/docs/1.0/graphql/manual/guides/integrations/auth0-jwt.html#create-an-auth0-application
Also additionally, how would one go about using the JWT Token and using it to make requests later on elsewhere in the app?
I'm not sure if this will answer your question but I had a similar issue the other day.
https://github.com/iaincollins/next-auth/issues/270#issuecomment-644597355
What I had to do is go to
import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
const options = {
site: 'http://localhost:3000',
providers: [
Providers.GitHub({
clientId: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
scope: 'user',
}),
],
callbacks: {
redirect: async (url, baseUrl) => {
return url.startsWith(baseUrl)
? Promise.resolve(url)
: Promise.resolve(baseUrl)
},
session: async (session, token) => {
return Promise.resolve(token)
},
jwt: async (token, oAuthProfile) => {
return Promise.resolve(token)
}
},
session: {
jwt: true
}
}
I had to activate turn on jwt in the session object. Then I had to resolve the Promise that was returned and after all that I returned the token within the session 馃檹 . Hope this somehow helps you out. Someone correct me if I did it incorrectly but yeah good luck!
I think an approach like this should work. If you want to read the Auth0 token you may also need to set idToken: true in the options passed to Providers.Auth0().
I'll give this a go when I get some time and let you know what I find, seems like it would be useful to have it documented how to use the SPA mode with JWT!
@softwaredeveloptam: This did help as I'm now able to see the auth code come in.
However what I'm seeking is the id_token from Auth0. It's available via Auth0's Implicit Flow but also in their Authorization Code Grant Flow with PKCE. But for this one, there's an added step after getting the Auth Code to gain the Access Token (or in my case, ID Token).
{
"access_token": "eyJz93a...k4laUWw",
"refresh_token": "GEbRxBN...edjnXbL",
"id_token": "eyJ0XAi...4faeEoQ",
"token_type": "Bearer"
}
@iaincollins: Thanks! Would appreciate it if you could see how to do this over with Auth0's SPA with JWT.
I had a look and it looks like the Auth0 provider we are shipping works great with both Single Page Apps and the JWT Token ID support in Auth0. :-)
You don't actually need to use Auth0's JWT to use JWT with NextAuth.js, but if you want to for any reason, is what it looks like:
import NextAuth from 'next-auth'
import Providers from 'next-auth/providers'
const options = {
site: process.env.SITE,
providers: [
Providers.Auth0({
clientId: process.env.AUTH0_ID,
clientSecret: process.env.AUTH0_SECRET,
domain: process.env.AUTH0_DOMAIN,
idToken: true
})
],
// Documentation for callbacks: https://next-auth.js.org/configuration/callbacks
callbacks: {
// The JWT callback is called any time a token is written to
jwt: async (token, oAuthProfile) => {
// * The first argument is the NextAuth.js token.
// * The second argument is the full profile returned by the Provider.
// The second argument is only present on the first write (token)
// If tokenId is used (must be supported by the provider) it will be the
// the contents of the token from the provider.
const isSignIn = oAuthProfile ? true : false
console.log('NextAuth.js JWT', token)
console.log('Provider profile', oAuthProfile)
// Return the object you want to be stored in the token here
// e.g. `token.auth0 = oAuthProfile`
// Note: Try to only store information you need in the JWT to avoid the
// cookie size growing too large (should not exceed 4KB)
return Promise.resolve(token)
},
// The session callback is called before a session object is returned to the client
session: async (session, token) => {
// The first object is the default session contents that is returned
// The second object is the NextAuth.js JWT (aways passed if JWT enabled)
console.log('NextAuth.js session and token', session, token)
// As with the JWT, you can add properties to the 'session' object
// from the 'token' here (e.g. `session.someProperty = token.someProperty`)
return Promise.resolve(session)
},
},
}
export default (req, res) => NextAuth(req, res, options)
I say I don't think you need it as the response doesn't have anything special in it.
This is the NextAuth.js JWT after signing in with Google via Auth0 :
{
user: {
name: 'me',
email: '[email protected]',
image: 'https://lh3.googleusercontent.com/a-/AOh14GhNSgHeLUbMlLCPZA61EXdC2Dq0iIKJtna6KGmuta0'
},
account: {
provider: 'auth0',
type: 'oauth',
id: 'google-oauth2|114706867586664814765',
refreshToken: undefined,
accessToken: '***redacted***',
accessTokenExpires: null
},
isNewUser: undefined
}
This is the Auth0 JWT:
{
given_name: 'Iain',
family_name: 'Collins',
nickname: 'me',
name: 'Iain Collins',
picture: 'https://lh3.googleusercontent.com/a-/AOh14GhNSgHeLUbMlLCPZA61EXdC2Dq0iIKJtna6KGmuta0',
locale: 'en',
updated_at: '2020-06-23T12:10:44.172Z',
email: '[email protected]',
email_verified: true,
iss: 'https://dev-s6clz2lv.eu.auth0.com/',
sub: 'google-oauth2|114706867586664814765',
aud: 'jqUix1nj7w6u46ZDeil1kuL3ERT4GKe0',
iat: 1592914247,
exp: 1592950247
}
I think what you want is to just enable JWT (with the sessions: { jwt: true } option) - if you are not using a database with NextAuth.js it will be enabled automatically - and then use the NextAuth.js JWT to make requests.
To read the JWT from an API route, just pass the secret to the getJwt() method from an API route and it will decode it for you:
import jwt from 'next-auth/jwt'
const secret = process.env.JWT_SECRET
export default async (req, res) => {
// Automatically decrypts and verifies JWT
const token = await jwt.getJwt({ req, secret })
res.end(JSON.stringify(token, null, 2))
}
See the JWT option documentation for more information. It should be all you need if you have API routes making request to backend services.
However, if you want to pass a JWT to another service you will need to do some work yourself.
You will either need to:
JWT tokens used by NextAuth.js are encrypted as well as signed. This means they can be used to store data securely, but also means they can't easily be read by another service (unless it can be configured to use the same decryption routine).
It's a bit of a complex and confusing topic, but you'll need to work out what makes most sense for your situation.
The code for the JWT encode and decode options - and the getJwt() method - is thankfully quite simple:
import jwt from 'jsonwebtoken'
import CryptoJS from 'crypto-js'
const encode = async ({ secret, key = secret, token = {}, maxAge }) => {
// If maxAge is set remove any existing created/expiry dates and replace them
if (maxAge) {
if (token.iat) { delete token.iat }
if (token.exp) { delete token.exp }
}
const signedToken = jwt.sign(token, secret, { expiresIn: maxAge })
const encryptedToken = CryptoJS.AES.encrypt(signedToken, key).toString()
return encryptedToken
}
const decode = async ({ secret, key = secret, token, maxAge }) => {
if (!token) return null
const decryptedBytes = CryptoJS.AES.decrypt(token, key)
const decryptedToken = decryptedBytes.toString(CryptoJS.enc.Utf8)
const verifiedToken = jwt.verify(decryptedToken, secret, { maxAge })
return verifiedToken
}
You can view the source file this comes from here:
https://github.com/iaincollins/next-auth/blob/main/src/lib/jwt.js
Closing this as is answered.
In case anyone else ends up here looking for some clarification. I wanted to access the encoded Auth0 JWT, after performing login with next-auth, although this might also help with accessing the decoded JWT. There is some confusion in a lot of these github issues where people use the term 'JWT' without being specific, which I think leads to responses answering several different problems. I realise I'm just adding to that 馃槅 .
My (simplified) understanding of how it works is:
The biggest issue for me was in part 2, where Auth0 wasn't returning a JWT, but instead an opaque access token, which sent me on a hunt for the Auth0 JWT, as I'd incorrectly assumed next-auth was just repackaging it and throwing the original away.
If you're here looking for the Auth0 JWT but find that the account.accessToken field is not a JWT, you might need to specify an audience in the provider Authorization URL:
authorizationUrl: `https://<Your Auth0 Tenant>/authorize?response_type=code&audience=${encodeURI(<Your API Audience>)}`,
It seems like accessing the JWT of the provider, rather than next-auth is what some people get stuck with. In my case the issue wasn't really with next-auth, although perhaps the Auth0 provider needs updating?
馃憢 @MGough Auth0 doesn't recommend securing APIs with id tokens so we need JWT formed access tokens issued by Auth0. To get back JWT access token from Auth0, audience parameter is mandatory.
Have you checked custom provider option? It seems, it is possible to pass additional parameters with this provider. Until Auth0 provider supports audience, it may be an option perhaps.
馃憢 @iaincollins any comments?
馃憢 @MGough Auth0 doesn't recommend securing APIs with id tokens so we need JWT formed access tokens issued by Auth0. To get back JWT access token from Auth0, audience parameter is mandatory.
Have you checked custom provider option? It seems, it is possible to pass additional parameters with this provider. Until
Auth0provider supportsaudience, it may be an option perhaps.馃憢 @iaincollins any comments?
Hi @rsmcode , thanks for the response. My apologies that I wasn't very clear at the end there.
I've used the custom provider option, copying the existing Auth0 provider settings and modifying them to include audience. That resolved my issue, and I now have a JWT Access Token from Auth0 as I originally wanted.
I was hoping by posting here that I might help if anyone else finds themselves in the same scenario. Although it would be interesting to hear if anyone has any other thoughts on the issue.
I now realise this is slightly off topic, as I was not after the ID Token, I misread the original title!
@MGough thank you for the update. I was testing something similar for Cognito and I will revisit the custom provider.
I believe, your point isn't off topic. There are many misinterpretations of id tokens in the wild. Hasura link for Auth0 is clearly outdated. Auth0 rolled out APIs a few years ago and going forward any resource server like Hasura GraphQL API should benefit from it with a JWT formatted access token.
Most helpful comment
I had a look and it looks like the Auth0 provider we are shipping works great with both Single Page Apps and the JWT Token ID support in Auth0. :-)
You don't actually need to use Auth0's JWT to use JWT with NextAuth.js, but if you want to for any reason, is what it looks like:
I say I don't think you need it as the response doesn't have anything special in it.
This is the NextAuth.js JWT after signing in with Google via Auth0 :
This is the Auth0 JWT:
I think what you want is to just enable JWT (with the
sessions: { jwt: true }option) - if you are not using a database with NextAuth.js it will be enabled automatically - and then use the NextAuth.js JWT to make requests.To read the JWT from an API route, just pass the secret to the
getJwt()method from an API route and it will decode it for you:See the JWT option documentation for more information. It should be all you need if you have API routes making request to backend services.
However, if you want to pass a JWT to another service you will need to do some work yourself.
You will either need to:
JWT tokens used by NextAuth.js are encrypted as well as signed. This means they can be used to store data securely, but also means they can't easily be read by another service (unless it can be configured to use the same decryption routine).
It's a bit of a complex and confusing topic, but you'll need to work out what makes most sense for your situation.
The code for the JWT
encodeanddecodeoptions - and thegetJwt()method - is thankfully quite simple:You can view the source file this comes from here:
https://github.com/iaincollins/next-auth/blob/main/src/lib/jwt.js