JWT refresh (#636)

## Description:

Implement refresh for JWTs.

Related to https://github.com/openfrontio/infra/pull/26

## Please complete the following:

- [x] I have added screenshots for all UI updates
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

---------

Co-authored-by: Scott Anderson <662325+scottanderson@users.noreply.github.com>
This commit is contained in:
Scott Anderson
2025-05-02 15:02:53 -04:00
committed by GitHub
parent 0dd762e3a8
commit d6b100108a
2 changed files with 47 additions and 4 deletions
+5
View File
@@ -1,6 +1,11 @@
import { z } from "zod";
import { base64urlToUuid } from "./Base64";
export const RefreshResponseSchema = z.object({
token: z.string(),
});
export type RefreshResponse = z.infer<typeof RefreshResponseSchema>;
export const TokenPayloadSchema = z.object({
jti: z.string(),
sub: z
+42 -4
View File
@@ -1,5 +1,6 @@
import { decodeJwt } from "jose";
import {
RefreshResponseSchema,
TokenPayload,
TokenPayloadSchema,
UserMeResponse,
@@ -97,10 +98,17 @@ export function _isLoggedIn(): TokenPayload | false {
localStorage.removeItem("token");
return false;
}
// const maxAge: number | undefined = undefined;
// if (iat !== undefined && maxAge !== undefined && now >= iat + maxAge) {
// // TODO: Refresh token...
// }
const refreshAge: number = 6 * 3600; // 6 hours
if (iat !== undefined && now >= iat + refreshAge) {
console.log("Refreshing access token...");
postRefresh().then((success) => {
if (success) {
console.log("Refreshed access token successfully.");
} else {
console.error("Failed to refresh access token.");
}
});
}
const result = TokenPayloadSchema.safeParse(payload);
if (!result.success) {
@@ -120,6 +128,36 @@ export function _isLoggedIn(): TokenPayload | false {
}
}
export async function postRefresh(): Promise<boolean> {
try {
const token = getToken();
if (!token) return false;
// Refresh the JWT
const response = await fetch(getApiBase() + "/refresh", {
method: "POST",
headers: {
authorization: `Bearer ${token}`,
},
});
if (response.status !== 200) return false;
const body = await response.json();
const result = RefreshResponseSchema.safeParse(body);
if (!result.success) {
console.error(
"Invalid response",
JSON.stringify(body),
JSON.stringify(result.error),
);
return false;
}
localStorage.setItem("token", result.data.token);
return true;
} catch (e) {
return false;
}
}
export async function getUserMe(): Promise<UserMeResponse | false> {
try {
const token = getToken();