Tomas Aschan
Tomas Aschan

Reputation: 60564

Refreshed OAuth2 token has invalid signature (Azure AD OAuth2)

I'm trying to create an authentication flow where the user's access token is kept in a server-side session along with the refresh token, and when the token expires it is renewed if the session is still valid. However, the token I get back from Azure AD after refresh has an invalid signature, when verifying it with the same method as the original token.

Here's a runnable gist that illustrates the problem: https://gist.github.com/tlycken/fdaf47dc31e03de43a1a07fbbea2ab91

What I'm doing is basically this:

  1. When the user requests a page, check for a session. If none exists, redirect to /auth which redirects to Azure AD, and when I'm returned I have a valid token which I store in the session.

  2. Verify the token from the session using jwks-rsa. (This normally works fine, so I'm purposely adding something to the token string to make the signature invalid in the test code.)

  3. If token verification failed, and there is a refresh token on the session, try to fetch a new token using that refresh token. This request normally returns with status 200 OK and a new set of access/refresh tokens.

  4. Verify the new access token using the same code as was used to verify the old one (now without garbling the token). This should work, IIUC, but it fails with the error invalid signature.

Why does my newly refreshed token not pass verification?

Update: I was able to create a simpler flow for reproducing this; the gist has been updated. It now does the following (printing these messages, along the way):

no session, redirecting to /auth
successful auth callback, redirecting to /
verifying old token
decoded user id e7f02a6e-510c-430d-905c-f8a0e63206c2
refreshing
fetching /me with renewed token
got user id e7f02a6e-510c-430d-905c-f8a0e63206c2
verifying new token
token verification failed: invalid signature

In addition to validating the token myself, I now also send a request to Azure with it, hoping that such a request would fail for an invalid token. But it passes!

Upvotes: 10

Views: 2743

Answers (1)

Marc LaFleur
Marc LaFleur

Reputation: 33094

You're code is using the v1 Endpoint to obtain the initial access token but the v2 Endpoint to exorcise the refresh token. These two endpoints operate differently. In particular, the v1 Endpoint uses "resource" while v2 uses "scopes".

The reason this is happening is your calling v1 explicitly but relying on the v2 /openid-configuration for the Refresh Token endpoint.

To correct this, change line 19 of refresh-auth-token.js to

const configResponse = 
   await fetch(`https://login.microsoftonline.com/${AZURE_TENANT}/.well-known/openid-configuration`)

Upvotes: 3

Related Questions