Skip to content

Commit a7594c1

Browse files
committed
Update the function and add types
1 parent 57fbfc0 commit a7594c1

File tree

2 files changed

+76
-74
lines changed

2 files changed

+76
-74
lines changed
Lines changed: 51 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,109 +1,86 @@
1-
import jwksClient from "jwks-rsa";
2-
import JsonWebToken from "jsonwebtoken";
3-
import type { JwtHeader, JwtPayload, SigningKeyCallback } from "jsonwebtoken";
4-
1+
import jose from "jose";
52
import { cookies, headers } from "next/headers";
63
import { redirect } from "next/navigation";
74

5+
import SuperTokens from "../../../superTokens";
6+
7+
import type { AccessTokenPayload, LoadedSessionContext } from "../types";
8+
89
// const ACCESS_TOKEN_NAME = "st-access-token";
910
const ACCESS_TOKEN_NAME = "sAccessToken";
1011
const FRONT_TOKEN_NAME = "sFrontToken";
1112

12-
const REFRESH_TOKEN_PATH = "/api/refresh";
13-
const AUTH_PATH = "/auth";
14-
1513
// TODO:
16-
// - Update the api paths based on the SDK config
1714
// - Add error handling
1815
// - Figure out the correct token name. Is it sAccessToken or st-access-token?
19-
export async function getSessionOrRedirect() {
16+
export async function getSessionOrRedirect(): Promise<LoadedSessionContext> {
2017
const headersList = await headers();
2118
const cookieStore = await cookies();
22-
2319
const frontToken = cookieStore.get(FRONT_TOKEN_NAME)?.value;
24-
20+
const authPagePage = getWebsiteBasePath();
2521
if (!frontToken) {
26-
redirect(AUTH_PATH);
22+
redirect(authPagePage);
2723
}
2824

29-
// const lastAccessTokenUpdate = cookieStore.get(LAST_ACCESS_TOKEN_UPDATE)?.value;
30-
// if (!lastAccessTokenUpdate) {
31-
// redirect(REFRESH_TOKEN_PATH);
32-
// }
33-
// const parsedLastAccessTokenUpdate = parseInt(lastAccessTokenUpdate);
34-
25+
const refreshTokenPath = `${getApiBasePath()}/refresh`;
3526
const parsedFrontToken = parseFrontToken(frontToken);
3627
if (parsedFrontToken.up?.exp && parsedFrontToken.up.exp < Date.now()) {
37-
redirect(REFRESH_TOKEN_PATH);
28+
redirect(refreshTokenPath);
3829
}
3930

4031
const accessToken = cookieStore.get(ACCESS_TOKEN_NAME)?.value || headersList.get(ACCESS_TOKEN_NAME);
4132
if (!accessToken) {
4233
// TODO: Should redirect to auth page?
43-
redirect(REFRESH_TOKEN_PATH);
34+
redirect(refreshTokenPath);
4435
}
4536

46-
const parsedAccessToken = await verifyToken(accessToken);
47-
if (!areTokenPayloadsEqual(parsedFrontToken, parsedAccessToken)) {
48-
redirect(REFRESH_TOKEN_PATH);
37+
const parsedAccessToken = await parseAccessToken(accessToken);
38+
if (!comparePayloads(parsedFrontToken, parsedAccessToken)) {
39+
redirect(refreshTokenPath);
4940
}
5041

51-
// TODO: Return the actual session object
52-
return {};
42+
return {
43+
userId: parsedAccessToken.up.sub,
44+
accessTokenPayload: parsedAccessToken,
45+
doesSessionExist: true,
46+
loading: false,
47+
invalidClaims: [],
48+
accessDeniedValidatorError: undefined,
49+
};
5350
}
5451

55-
function parseFrontToken(frontToken: string): TokenPayload {
56-
return JSON.parse(decodeURIComponent(escape(atob(frontToken))));
57-
}
52+
const getApiBasePath = () => {
53+
return SuperTokens.getInstanceOrThrow().appInfo.apiBasePath.getAsStringDangerous();
54+
};
5855

59-
type TokenPayload = {
60-
uid: string;
61-
ate: number;
62-
up: {
63-
iat: number;
64-
exp: number;
65-
sub: string;
66-
tId: string;
67-
rsub: string;
68-
sessionHandle: string;
69-
refrehTokenHash1: string;
70-
parentRefereshTokenHash1: string | null;
71-
antiCsrfToken: string | null;
72-
iss: string;
73-
"st-role": {
74-
v: string;
75-
t: number[];
76-
};
77-
"st-perm": {
78-
v: string[];
79-
t: number;
80-
};
81-
};
56+
const getWebsiteBasePath = () => {
57+
return SuperTokens.getInstanceOrThrow().appInfo.websiteBasePath.getAsStringDangerous();
8258
};
8359

84-
const client = jwksClient({
85-
jwksUri: `<api-domain>/<api-base-path>/jwt/jwks.json`,
86-
});
60+
function parseFrontToken(frontToken: string): AccessTokenPayload {
61+
return JSON.parse(decodeURIComponent(escape(atob(frontToken))));
62+
}
8763

88-
async function verifyToken(token: string): Promise<JwtPayload> {
89-
const getPublicKey = (header: JwtHeader, callback: SigningKeyCallback) => {
90-
client.getSigningKey(header.kid, (err, key) => {
91-
if (err) {
92-
callback(err);
93-
} else {
94-
const signingKey = key?.getPublicKey();
95-
callback(null, signingKey);
96-
}
97-
});
98-
};
64+
async function parseAccessToken(token: string): Promise<AccessTokenPayload> {
65+
const JWKS = jose.createRemoteJWKSet(new URL(`${getApiBasePath()}/authjwt/jwks.json`));
66+
const { payload } = await jose.jwtVerify(token, JWKS);
67+
return payload;
68+
}
9969

100-
return new Promise((resolve, reject) => {
101-
JsonWebToken.verify(token, getPublicKey, {}, (err, decoded) => {
102-
if (err) {
103-
reject(err);
104-
} else {
105-
resolve(decoded as JwtPayload);
106-
}
107-
});
108-
});
70+
function comparePayloads(payload1: AccessTokenPayload, payload2: AccessTokenPayload): boolean {
71+
return (
72+
payload1.uid === payload2.uid &&
73+
payload1.ate === payload2.ate &&
74+
payload1.up.sub === payload2.up.sub &&
75+
payload1.up.tId === payload2.up.tId &&
76+
payload1.up.sessionHandle === payload2.up.sessionHandle &&
77+
payload1.up.refrehTokenHash1 === payload2.up.refrehTokenHash1 &&
78+
payload1.up.parentRefereshTokenHash1 === payload2.up.parentRefereshTokenHash1 &&
79+
payload1.up.antiCsrfToken === payload2.up.antiCsrfToken &&
80+
payload1.up.iss === payload2.up.iss &&
81+
payload1.up["st-role"].v === payload2.up["st-role"].v &&
82+
payload1.up["st-role"].t.toString() === payload2.up["st-role"].t.toString() &&
83+
payload1.up["st-perm"].v.toString() === payload2.up["st-perm"].v.toString() &&
84+
payload1.up["st-perm"].t === payload2.up["st-perm"].t
85+
);
10986
}

lib/ts/recipe/session/types.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,28 @@ export type AccessDeniedThemeProps = {
7575
export type ComponentOverrideMap = {
7676
SessionAccessDenied_Override?: ComponentOverride<typeof AccessDeniedScreenTheme>;
7777
};
78+
79+
export type AccessTokenPayload = {
80+
uid: string;
81+
ate: number;
82+
up: {
83+
iat: number;
84+
exp: number;
85+
sub: string;
86+
tId: string;
87+
rsub: string;
88+
sessionHandle: string;
89+
refrehTokenHash1: string;
90+
parentRefereshTokenHash1: string | null;
91+
antiCsrfToken: string | null;
92+
iss: string;
93+
"st-role": {
94+
v: string;
95+
t: number[];
96+
};
97+
"st-perm": {
98+
v: string[];
99+
t: number;
100+
};
101+
};
102+
};

0 commit comments

Comments
 (0)