🧪 Test Token Refresh
Test that expired access tokens are refreshed correctly in your middleware.
Now that the middleware has been updated to handle token refreshing, let's run some tests to ensure that it's working correctly.
Prerequisites
Add Middleware Log Statements
Since the tokens are stored in an encrypted cookie, it's not possible to inspect them. Therefore, to see the new access tokens get created, you'll need to add a couple of log statements to your middleware, as shown in the code example below.
Never log token data outside of this test scenario
For security reasons, you should never log any token data. This approach is only intended for testing purposes. Make sure to remove the log statements after testing is done.
//
// Middleware for Both Page Router and App Router
// Location -> src/middleware.ts
//
import { NextRequest, NextResponse } from 'next/server';
import { wristbandAuth } from '@/wristband-auth';
import { middlewareGetSession } from '@/session/session';
import { isCsrfTokenValid, setCsrfTokenCookie } from '@/utils/csrf';
...
export async function middleware(req: NextRequest) {
const res = NextResponse.next();
if (!isProtectedRequest(req)) {
return res;
}
const session = await middlewareGetSession(req, res);
const { accessToken, expiresAt, refreshToken, csrfSecret, isAuthenticated } = session;
if (!isAuthenticated) {
return unauthorizedResponse(req);
}
try {
const tokenData = await wristbandAuth.refreshTokenIfExpired(refreshToken, expiresAt);
if (tokenData) {
/* ***** BEGIN TEST LOGS ***** */
console.log(`Old access token: [${accessToken}], new access token: [${tokenData.accessToken}]`);
console.log(`Old expiresAt: [${expiresAt}], new expiresAt: [${Date.now() + tokenData.expiresIn * 1000}]`);
/* ***** END TEST LOGS ***** */
session.expiresAt = Date.now() + tokenData.expiresIn * 1000;
session.accessToken = tokenData.accessToken;
session.refreshToken = tokenData.refreshToken;
}
} catch (error) {
console.log(`Token refresh failed: `, error);
return unauthorizedResponse(req);
}
if (isCsrfProtectedRequest(req)) {
const isValidCsrf = await isCsrfTokenValid(req, csrfSecret);
if (!isValidCsrf) {
return NextResponse.json({ statusText: 'Forbidden' }, { status: 403 });
}
}
await setCsrfTokenCookie(csrfSecret, res);
await session.save();
return res;
}
...
1. Test With a Valid Access Token
First, let's test the middleware with a non-expired access token. In this case, the access token should not be refreshed because it's still valid.
Test Steps
- Navigate to your tenant's Login Page and complete the login flow.
Verification Checks
- Inspect the console logs printed by your server. You should not see any log statements indicating that a new access token was created since the access token was still valid.
2. Test With An Expired Access Token
Next, we'll simulate having an expired access token by altering the middleware code to pass in a low expiresAt
value. For example:
//
// Middleware for Both Page Router and App Router
// Location -> src/middleware.ts
//
import { NextRequest, NextResponse } from 'next/server';
import { wristbandAuth } from '@/wristband-auth';
import { middlewareGetSession } from '@/session/session';
import { isCsrfTokenValid, setCsrfTokenCookie } from '@/utils/csrf';
...
export async function middleware(req: NextRequest) {
...
try {
// Pass a low expiresAt value (epoch time in millis) to force a refresh to occur.
const tokenData = await wristbandAuth.refreshTokenIfExpired(refreshToken, 100);
...
}
...
Test Steps
- While still logged into your application, click the refresh button to reload your application. This should trigger a call to your Session Endpoint, which in turn will invoke the middleware. When the middleware runs, it should see that your access token has expired and attempt to refresh it.
Verification Checks
- Verify that you can still access your application.
- Inspect the console logs printed by your server. You should see log statements indicating that both the
accessToken
andexpiresAt
values have been updated.
3. Test With a Revoked Refresh Token
Finally, let's revoke the refresh token from the Wristband Dashboard and verify that the token refresh now fails.
Test Steps
-
Make sure that the
expiresAt
value in your middleware is still set to a low value, so the access token gets marked as expired, triggering a token refresh. -
In the Wristband Dashboard, revoke the refresh token for the currently logged-in user:
-
From the Wristband Dashboard home page, navigate into your Wristband Application.
-
Select Users from the left navigation menu.
-
In the Users table, click on the row of your test user.
-
On that user's settings page, scroll down to the Refresh Token table. Here, you can see if the Wristband Auth Session was deleted from Wristband's backend (which is the source of auth sessions).
-
Click the Trash Can icon for the refresh token you need to revoke. You can alternatively revoke all refresh tokens for this user using the button under the table.
-
- Ensure that your browser's dev tools are actively monitoring network requests. Also, ensure that network requests are configured to be preserved so you can examine them afterward.
- While still logged into your application, click the refresh button to reload your application. This should trigger a call to your Session Endpoint, which in turn will invoke the middleware. When the middleware runs, it should see that your access token has expired and attempt to refresh it; however, this time, it should fail since the user's refresh token has been revoked.
Verification Steps
-
In your browser's developer tools, find the network request to your application's Session Endpoint. Verify that the response is a 401.
-
Verify that you are redirected to your application's Login Endpoint and that you land on Wristband's hosted Login Page.
-
Inspect the console logs printed by your server. You should not see any log statements indicating that a new access token was created since the refresh token operation failed.
Revert Your
expiresAt
Code ChangeOnce this test is verified, undo the code change from above so that the
expiresAt
value from your session is passed as an argument into the SDK instead of your hardcoded test value.
Remove Your Log Statements
Just one more friendly reminder to remove log statements containing token data. 🙂
If all tests succeed, then the token refresh logic is working as expected. 🎉

You did it. Fresh tokens are coming right up!
Updated 8 days ago
This is just the beginning -- there's so much more you can build with our platform! Let's explore.