Getting invalid token from client using react-auth0-spa.js

I’ve been spending days trying get this working, and I’m close but at this point I’m always getting invalid token on the server when verifying it the token sent up from the client.

Here’s what I got:

React client (with apollo) that uses react-auth0-spa.js
Here’s the settings:

{
  "domain": "myappdomain.auth0.com", // domain from Auth0 SPA app
  "clientId": "FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp", // client id from Auth0 SPA app
  "audience": "https://api.myappdomain.com" // from a newly created API on Auth0
}

Using the ApolloClient, I am able to successfully getTokenSilently(). I send it up with the “Bearer” prefix.

ApolloServer node server
In the context function I am able to retrieve the same token from the request.headers.authorization with Bearer prefix (shown below). I then utilize jsonwebtoken library to verify the token, but it ALWAYS gives JsonWebTokenError: invalid token. Here’s what the token looks like:

Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlEwTTJSRFUwTkRjM01UUTNPVGxGTUVJd09FUkdNa0kzUkVJeFFVUkZSamxDTlRJMU5UWXhNUSJ9.eyJpc3MiOiJodHRwczovL3RydXRoeC5hdXRoMC5jb20vIiwic3ViIjoiZ29vZ2xlLW9hdXRoMnwxMTI2NzEyMTU3MjUwNDk2NDE5OTciLCJhdWQiOlsiaHR0cHM6Ly9hcGkudHJ1dGh4LmFwcCIsImh0dHBzOi8vdHJ1dGh4LmF1dGgwLmNvbS91c2VyaW5mbyJdLCJpYXQiOjE1NzgxMjIxODUsImV4cCI6MTU3ODIwODU4NSwiYXpwIjoiRnN0QkVXYmJXWVpGand5aTBVYlUxck5raENJMV93cXAiLCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIn0.2Sk0vy8f77sPvmoU1yp9xD7Nm-ajEXfJd6dEUoL66dZ6vcqQ1aKGYyppjqpjP-RyZXj77QVvkXxbTtB3Es3fnMh6sBkF4xE1mVsIkJWLt1RvRV9OZVvrgG612GHmxRPBbLIap17XfPH12Oj5kQIKMa_XkWELAXVxCmW1p-gIg0vGcurh8Rh_qrJVVQWta2Je87mnSDbdl2vuKhUPLp3SixV5IlBhTBSs40UBRtH5pUPldJBb43yZdZ5tnwHCgAm_jgwBfWiJDHG2e4a70w3ZPpDDGYr2UGCjN2gaIqDbhMdkf4A0m_oeaa1LRoRRM5OyxQ5IzRASOYkZ09tog-fCug


Here’s the server code that verifies it:

const jwt = require("jsonwebtoken");
// ...
const options = {
  audience: "FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp'", // which is my AUTH_CLIENT_ID
  issuer: `https://myappdomain.com/`,
  algorithms: ["RS256"]
};

jwt.verify(
      token,
      "<MY_CLIENT_SECRET_KEY>",
      options,
      (err, decoded) => {
        console.log("err);
        if (err) throw new AuthenticationError("You must be logged in");
        // ...
      }
 );

The error is always JsonWebTokenError: invalid token.

NOW, if I change the <MY_CLIENT_SECRET_KEY> to a PEM encoded public key that I get from the Auth0 SPA advanced settings, I get this error:
{ JsonWebTokenError: jwt audience invalid. expected: FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp
But that IS the audience value I give in the options, so I don’t get it.

Any ideas?

Hi garym, and welcome to the community! :tada:

I noticed your audience is being set as:

FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp’

But the expected audience does not have the single quote on the end:

FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp

Have you tried removing the extra single quote and seeing if that works?

Hello Thomas, thank you for your reply (and pardon my delay in getting back).

That extra single quote was an accidental typo in my forum post only, so unfortunately that is not it. I’ve confirmed the settings while reviewing pages like your guys’ react/graphql/apollo article and I can’t seem to find what is amiss.

Just to confirm: on the client side, the audience is the API identifier given by a separate API application created in the Auth0 dashboard (looks like “https://api.myappdomain.com”).

On the server side, my audience is the AUTH0_CLIENT_ID (as indicated in above article) found in my Web Application created in Auth0 dashboard and issuer is my auth0 domain (e.g. myappdomain.auth0.com). Interestingly, on another article of yours regarding express/auth0, it says to set audience as YOUR_API_IDENTIFIER which is different. I’ve tried both ways (and other various tests) and I am still getting the below error in the server:

{ JsonWebTokenError: invalid token
    at Object.module.exports [as verify] (/home/gary/development/myapp/api/node_modules/jsonwebtoken/verify.js:75:17)
    at ApolloServer.context (/home/gary/development/myapp/api/src/index.js:67:7)
    at ApolloServer.<anonymous> (/home/gary/development/myapp/api/node_modules/apollo-server-core/src/ApolloServer.ts:737:24)
    at Generator.next (<anonymous>)
    at fulfilled (/home/gary/development/myapp/api/node_modules/apollo-server-core/dist/ApolloServer.js:5:58)
    at process._tickCallback (internal/process/next_tick.js:68:7) name: 'JsonWebTokenError', message: 'invalid token' }

I’ve checked again and as I indicated in my first post, the server IS receiving the token from the client as shown in first post (with the "Bearer " prefix) and that’s what I give as my first argument in jwt.verify(). Any help is very much appreciated.

Interesting. I’ve been trying different variations and I found something that didn’t result in an error.

First, I removed the prefix "Bearer " on the token before using it. Then I tried the secret key in jwt.verify(token, secretOrPublicKey, option) which resulted in the same invalid token. Yet when I tried my PEM encoded public key, it resulted in invalid audience with a recommended setting of ‘FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp’, which is the exact audience setting I DO have in the options object. On a whim, I then tried commenting out the audience in options:

const options = {
  // audience: "FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp",
  issuer: "https://myappdomain.auth0.com/",
  algorithms: ["RS256"]
};

And when I use that, the call succeeds and the result is:

{
  iss: 'https://myappdomain.auth0.com/',
  sub: 'auth0|5e1a5d134659590cc78665f5',
  aud:
   [ 'https://api.myappdomain.com',
     'https://myappdomain.auth0.com/userinfo' ],
  iat: 1578893195,
  exp: 1578979595,
  azp: 'FstBEWbbWYZFjwyi0UbU1rNkhCI1_wqp',
  scope: 'openid profile email'
}

Is that correct? And if correct, why would the aforementioned articles (here and here) all mention the inclusion of audience in the options? And why would this ONLY work with the publicKey option and not secret key as also stated in the docs? Please help clarify.

Hi garym,

Sorry for the delay in getting back to you.

Per the RFC, the audience is optional when verifying the token. We choose to include it in our guides but it is not required.

In your situation, I believe the correct audience would be " [ ‘https://api.myappdomain.com’,
https://myappdomain.auth0.com/userinfo’ ]" as this is the audience listed in the token.

Could you tell me where in the docs it instructed you to use the private key? I could not find that in the documentation you linked me (but maybe I missed it as they are quite long).