Tom Oakley Tom Oakley - 1 year ago 174
Javascript Question

Get Auth0 access_token from existing id_token

I'm using auth0 to authenticate my logins to my Single Page App (built on React). I'm mostly using the base API calls (listed here).

The process I'm using is:

get username/email and password when the user enters them on my app's login page
Send a POST request to

with those values - here is that code:

export const login = (params, err) => {
if (err) return err
const {email, password} = params
const {AUTH0_CLIENT_ID, AUTH0_DOMAIN} = process.env
return fetch(`${AUTH0_DOMAIN}/oauth/ro`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
body: JSON.stringify({
'client_id': AUTH0_CLIENT_ID,
'username': email,
'password': password,
'connection': 'Username-Password-Authentication',
'grant_type': 'password',
'scope': 'openid',
'device': '',
'id_token': ''
.then(response => response.json())
.then(json => {
const {id_token, access_token} = json
setCookieValue('id_token', id_token) // utility function I wrote
return getProfile(access_token)
.then(data => {
const {user_id, email: emailAddress, picture, name} = data
return {id_token, user_id, emailAddress, picture, name}
.catch(error => console.log(`ERROR: ${error}`))

This is all sent through Redux and the user is logged in (assuming the username/password was correct).

However, I'm trying to figure out how to persist the login when refreshing the page/coming back to the app. I'm saving the
(which is a JWT) in the browser's cookies and can fetch this when the app renders server-side. I can decode the JWT and get the payload (
is the user ID from auth0). However, to get the profile data I need the
which Auth0 provides when using the
POST request. Obviously, if the JWT token has expired then it will just reject it and keep the user logged out.

Here is my code to decode the JWT (happens on app render):

const ID_TOKEN = req.cookies.id_token || false
if (ID_TOKEN) {
verifyJwt(ID_TOKEN, (err, decoded) => {
if (err) { console.log(`JWT Verification error: ${err}`) }
else {
const {sub} = decoded
getProfile(sub).then(data => store.dispatch(fetchUserDetails(data))) // fails as `sub` (the user id) is not the `access_token` which it requires

I have tried using the
call again, but this time specifying
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer"
and using the
retrieved from the cookies, and specifying a
. However, when I do this call, I get this error from Auth0:

"error": "invalid_request",
"error_description": "there is not an associated public key for specified client_id/user_id/device"

So my question is, what API call do I need to make to get the
from the

Also, as a bonus - when I do the POST request to login, the
is being transfered over plaintext. How would I encrypt this when sending to auth0 so they can decrypt it back? I assume it involves using the
which auth0 provide but I'm not sure how to go about doing that.

Answer Source

The ability to refresh a token programmatically without any type of user interaction is accomplished through the use of refresh tokens. However, this is not applicable for browser-based applications because refresh tokens are long-lived credentials and the storage characteristics for browsers would place them at a too bigger risk of being leaked.

If you want to continue to use the resource owner password credentials grant you can choose to ask the user to input the credentials again when the tokens expire. As an alternative, upon authentication you can obtain the required user information and initiate an application specific session. This could be achieved by having your server-side logic create an application specific session identifier or JWT.

You can also stop using the resource owner password credentials grant and redirect the user to an Auth0 authentication page that besides returning the tokens to your application would also maintain an authenticated session for the user, meaning that when the tokens expired and your application redirected again to Auth0, the user might not need to manual reenter credentials because the Auth0 session is still valid.

In relation to the password being sent in plaintext; the resource owner endpoint relies on HTTPS so the data is encrypted at the protocol level. You must also use HTTPS within your own application for any type of communication that includes user credentials of any kind.

Also note that you can control what's returned within the ID token through the use of scopes, depending on the amount of information in question you might not even need to make additional calls to get the user profiles if you signal that you want that information to be contained within the ID token itself.