Created backend token manager for automatic access token refresh#50
Created backend token manager for automatic access token refresh#50Mehulantony wants to merge 1 commit intomainfrom
Conversation
|
|
||
| try { | ||
| const payload = JSON.parse( | ||
| Buffer.from(token.split('.')[1], 'base64').toString() |
There was a problem hiding this comment.
Guard against malformed tokens
It may be safer to add a check to ensure the token has the expected JWT structure before attempting to decode it.
if (parts.length !== 3) return true;
This prevents errors if the token is malformed or not actually a JWT.
Also, consider using jsonwebtoken.decode() instead of manually decoding with Buffer.from(...), since it handles Base64URL encoding and parsing more robustly.
| "express": "^5.2.1", | ||
| "express-oauth2-jwt-bearer": "~1.7.1", | ||
| "express-urlrewrite": "~2.0.3", | ||
| "jsonwebtoken": "^9.0.3", |
There was a problem hiding this comment.
We add "jsonwebtoken "as a dependency but don’t appear to use it in "token-manager". Do we plan to use it for decoding/verifying tokens here? If not, maybe we can either (
a) use it for "isTokenExpired" instead of manual parsing, or
(b) drop the dependency for now to keep the surface area smaller.
| import config from '../config/index.js' | ||
| import fs from 'node:fs/promises' | ||
|
|
||
| const sourcePath = '.env' |
There was a problem hiding this comment.
"sourcePath" is hard-coded to .env relative to the process CWD. In some deployment setups (docker) this might not point to the right file or might silently fail. Should we either
(a) make this path configurable
(e.g. process.env.ENV_FILE_PATH ?? '.env'`), or
(b) clearly document that this is intended as a local-dev convenience only?
| body: JSON.stringify({ refresh_token: refreshToken }) | ||
| }) | ||
|
|
||
| const tokenObject = await response.json() |
There was a problem hiding this comment.
If the token endpoint responds with non‑JSON (e.g. an HTML error page), response.json() will throw before we can check response.ok. Consider wrapping the json() call in a try/catch and surfacing a clearer error message (including HTTP status) when parsing fails.
| ) | ||
| } | ||
|
|
||
| process.env.ACCESS_TOKEN = tokenObject.access_token |
There was a problem hiding this comment.
This module mutates process.env at runtime, which is convenient but can be surprising if other parts of the app read env vars only at startup. Could we document this behavior prominently, and/or consider keeping the token in a module‑level variable and having callers always use getValidAccessToken() instead of reading from process.env directly?
| * using the stored refresh token | ||
| */ | ||
|
|
||
| async function checkAndRefreshAccessToken() { |
There was a problem hiding this comment.
With multiple concurrent requests, it’s possible that several callers all detect an expired token and call generateNewAccessToken() at the same time. Not a correctness bug, but it could result in unnecessary token refresh calls. Consider adding a simple in‑flight promise lock so that only one refresh happens at a time and others await it.
| Buffer.from(token.split('.')[1], 'base64').toString() | ||
| ) | ||
|
|
||
| return !payload.exp || Date.now() >= payload.exp * 1000 |
There was a problem hiding this comment.
We treat the token as expired exactly at exp. To be more robust to small clock skew between our server and the issuer, we might want to treat it as expired slightly before, e.g. subtracting 30 seconds from exp before comparing.
Created a backend token manager that handles automatic refresh of Auth0 access tokens using the existing refresh-token workflow. The implementation follows the approach used in TinyNode and preserves the current Auth0 registration/login flow.
The token manager checks whether the current access token is expired and, if necessary, requests a new access token using the stored refresh token. This moves token lifecycle management to the backend while keeping Auth0 as the source of truth for authentication.
It must be noted that the initial refresh token must still be obtained through the existing Auth0 UX registration/login flow.