How to Handle Expiring Netlify Identity JWT?

I discovered that the default expiration of a Netlify Identity JWT is 1 hour (3600 seconds).

access_token: "somethingsecret"
expires_at: 1597330572000
expires_in: 3600
refresh_token: "alsosecret"
token_type: "bearer"

As I type this, there the token will expire in ~30m mins and I logged in about a half hour ago.

If I use this token to call Netlify Identity API on behalf of the currentUser with this token and it has expired, naturally I will receive a 401 error.

But, Redwood still lets me use this token to access RW Private routes and call graphql and getCurrentUser returns the token (still with its expires_at time in the past).

Note: You it looks like one can [set the expiration via an ENV]:
(GitHub - netlify/gotrue: An SWT based API for managing users and issuing SWT tokens.)

GOTRUE_JWT_EXP - number

How long tokens are valid for, in seconds. Defaults to 3600 (1 hour).

Note: I have not gotten this to work (yet). Even when setting the ENV on Netlify’s deploy settings. I could not find a netlfiy widget setting here.

Options

So, what do we think Redood should do?

  1. If the token is expired, log them out immediately. Message why?
  2. Assume that in prod, Netlify will be checking the expiration. This deal dev. We cannot call jwt.verify() since to do not have the signing key. But maybe we can via GOTRUE_JWT_SECRET=supersecretvalue and then can use verify with that?
export const netlify = (token: string, req: { context: LambdaContext }) => {
  // Netlify verifies and decodes the JWT before the request is passed to our Serverless
  // function, so the decoded JWT is already available in production.
  if (process.env.NODE_ENV === 'production') {
    const clientContext = req.context.clientContext as NetlifyContext
    return clientContext?.user || null
  } else {
    // We emulate the native Netlify experience in development mode.
    // We just decode it since we don't have the signing key.
    return jwt.decode(token) // user verify()???
  }
}
  1. Should the web side try to refresh the token? (should the api side?)
// example from netlify go true

// refresh the user's JWT
// Note: this method returns a promise.
netlifyIdentity.refresh().then((jwt)=>console.log(jwt))

To start, I think I want to:

  • increase my JWT expires to 1 day (86400) Note: still have to figure out how to configiure this.
  • have the netlify auth provider call verify to check the expiration date with a custom set
    GOTRUE_JWT_SECRET used in dev and prod
  • or if cannot use verify, use decoded in development but also manually check the expiration claim similar to how jsonwebtoken does

BTW - Auth0’s getTokenSilently should refresh automatically.

Furthermore, getTokenSilently will then call the /oauth/token endpoint directly to exchange refresh tokens for access tokens.

So, does that mean the web side should also refresh if Netlify’s identity token is expired?

Ideas?

This is my favourite option - I think we pass the value of the token to the GraphQL client after you’ve authenticated, but I think we should pass a function that has the ability, per auth provider client, to understand when a token will expire and to refresh before handing a new token to the client.

1 Like

Ie - refresh the token on web side so that the JWT can be relatively short-lived (which is a very good thing) and then the user will continue to be able to use the app with an extended token.

I’ll write up a GH issue and can look into it.

1 Like

Thanks David, you’re a legend!

@dthyresson @peterp I had the same issue in Firebase Auth too. Here’s my Github issue - https://github.com/redwoodjs/redwood/issues/927

2 Likes

Thanks @hd10! I’ll reference that issue.

Useful to know so can have a general solution for (hopefully) all providers.

1 Like