Skip to content

Commit e730ba4

Browse files
committed
add JWT revocation list
1 parent b34fe8a commit e730ba4

File tree

2 files changed

+37
-2
lines changed

2 files changed

+37
-2
lines changed

src/api/plugins/auth.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,27 @@ const authPlugin: FastifyPluginAsync = async (fastify, _options) => {
265265
request.log.debug(
266266
`Start to verifying JWT took ${new Date().getTime() - startTime} ms.`,
267267
);
268-
request.tokenPayload = verifiedTokenData;
269-
request.username =
268+
// check revocation list for token
269+
const proposedUsername =
270270
verifiedTokenData.email ||
271271
verifiedTokenData.upn?.replace("acm.illinois.edu", "illinois.edu") ||
272272
verifiedTokenData.sub;
273+
const { redisClient, log: logger } = fastify;
274+
const revokedResult = await getKey<{ isInvalid: boolean }>({
275+
redisClient,
276+
key: `tokenRevocationList:${verifiedTokenData.uti}`,
277+
logger,
278+
});
279+
if (revokedResult) {
280+
fastify.log.info(
281+
`Revoked token ${verifiedTokenData.uti} for ${proposedUsername} was attempted.`,
282+
);
283+
throw new UnauthenticatedError({
284+
message: "Invalid token.",
285+
});
286+
}
287+
request.tokenPayload = verifiedTokenData;
288+
request.username = proposedUsername;
273289
const expectedRoles = new Set(validRoles);
274290
const cachedRoles = await getKey<string[]>({
275291
key: `${AUTH_CACHE_PREFIX}${request.username}:roles`,

src/api/routes/clearSession.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { FastifyPluginAsync } from "fastify";
22
import rateLimiter from "api/plugins/rateLimiter.js";
33
import { withRoles, withTags } from "api/components/index.js";
44
import { clearAuthCache } from "api/functions/authorization.js";
5+
import { setKey } from "api/functions/redisCache.js";
56

67
const clearSessionPlugin: FastifyPluginAsync = async (fastify, _options) => {
78
fastify.register(rateLimiter, {
@@ -26,7 +27,25 @@ const clearSessionPlugin: FastifyPluginAsync = async (fastify, _options) => {
2627
const username = [request.username!];
2728
const { redisClient } = fastify;
2829
const { log: logger } = fastify;
30+
2931
await clearAuthCache({ redisClient, username, logger });
32+
if (!request.tokenPayload) {
33+
return;
34+
}
35+
const now = Date.now() / 1000;
36+
const tokenExpiry = request.tokenPayload.exp;
37+
const expiresIn = Math.ceil(tokenExpiry - now);
38+
const tokenId = request.tokenPayload.uti;
39+
// if the token expires more than 10 seconds after now, add to a revoke list
40+
if (expiresIn > 10) {
41+
await setKey({
42+
redisClient,
43+
key: `tokenRevocationList:${tokenId}`,
44+
data: JSON.stringify({ isInvalid: true }),
45+
logger,
46+
expiresIn,
47+
});
48+
}
3049
},
3150
);
3251
};

0 commit comments

Comments
 (0)