11import { enableLogging , logDebugMessage } from "../logger" ;
22
3- import type { NextRequest , NextResponse } from "./types" ;
4- import type { SuperTokensConfig } from "../types" ;
3+ import type { NextRequest , NextResponse , SuperTokensNextjsConfig } from "./types" ;
54
65const ACCESS_TOKEN_COOKIE_NAME = "sAccessToken" ;
76const ACCESS_TOKEN_HEADER_NAME = "st-access-token" ;
@@ -10,83 +9,62 @@ const FRONT_TOKEN_HEADER_NAME = "front-token";
109const REFRESH_TOKEN_COOKIE_NAME = "sRefreshToken" ;
1110const REFRESH_TOKEN_HEADER_NAME = "st-refresh-token" ;
1211
13- export default class SuperTokensNextjsEdgeAPIWrapper {
14- static config : SuperTokensConfig ;
12+ let AppInfo : SuperTokensNextjsConfig [ "appInfo" ] ;
1513
16- static getConfigOrThrow ( ) : SuperTokensConfig {
17- if ( ! SuperTokensNextjsEdgeAPIWrapper . config ) {
18- throw new Error ( "SuperTokens must be initialized before calling this method." ) ;
19- }
20-
21- return SuperTokensNextjsEdgeAPIWrapper . config ;
14+ export function superTokensMiddleware ( config : SuperTokensNextjsConfig , request : NextRequest , response : NextResponse ) {
15+ AppInfo = config . appInfo ;
16+ if ( config . enableDebugLogs ) {
17+ enableLogging ( ) ;
2218 }
2319
24- static init ( config : SuperTokensConfig ) {
25- if ( config . enableDebugLogs ) {
26- enableLogging ( ) ;
27- }
28- SuperTokensNextjsEdgeAPIWrapper . config = config ;
20+ const url = new URL ( request . url ) ;
21+ const shouldRefresh = url . searchParams . get ( "forceRefresh" ) === "true" ;
22+ if ( shouldRefresh ) {
23+ return refreshSession ( request , response ) ;
2924 }
3025
31- static middleware ( request : NextRequest , response : NextResponse ) {
32- const url = new URL ( request . url ) ;
33- const shouldRefresh = url . searchParams . get ( "forceRefresh" ) === "true" ;
34- if ( shouldRefresh ) {
35- return refreshSession ( request , response ) ;
36- }
26+ // Save the current path so that we can use it during SSR
27+ // Used to redirect the user to the correct path after login/refresh
28+ return response . next ( {
29+ headers : {
30+ "x-current-path" : url . pathname ,
31+ } ,
32+ } ) ;
33+ }
3734
38- // Save the current path so that we can use it during SSR
39- // Used to redirect the user to the correct path after login/refresh
40- return response . next ( {
41- headers : {
42- "x-current-path" : url . pathname ,
43- } ,
44- } ) ;
35+ async function refreshSession ( request : NextRequest , response : NextResponse ) : Promise < NextResponse > {
36+ const refreshToken =
37+ request . cookies . get ( REFRESH_TOKEN_COOKIE_NAME ) ?. value || request . headers . get ( REFRESH_TOKEN_HEADER_NAME ) ;
38+ if ( ! refreshToken ) {
39+ logDebugMessage ( "Refresh token not found" ) ;
40+ return redirectToAuthPage ( request , response ) ;
4541 }
4642
47- static async refreshSession ( request : NextRequest , response : NextResponse ) : Promise < NextResponse > {
48- const refreshToken =
49- request . cookies . get ( REFRESH_TOKEN_COOKIE_NAME ) ?. value || request . headers . get ( REFRESH_TOKEN_HEADER_NAME ) ;
50- if ( ! refreshToken ) {
51- logDebugMessage ( "Refresh token not found" ) ;
43+ try {
44+ const tokens = await fetchNewTokens ( refreshToken ) ;
45+ if ( ! tokens . accessToken || ! tokens . refreshToken || ! tokens . frontToken ) {
46+ logDebugMessage ( "Missing tokens from refresh response" ) ;
5247 return redirectToAuthPage ( request , response ) ;
5348 }
5449
55- try {
56- const tokens = await fetchNewTokens ( refreshToken ) ;
57- if ( ! tokens . accessToken || ! tokens . refreshToken || ! tokens . frontToken ) {
58- logDebugMessage ( "Missing tokens from refresh response" ) ;
59- return redirectToAuthPage ( request , response ) ;
60- }
61-
62- const redirectUrl = new URL ( request . url ) ;
63- redirectUrl . searchParams . delete ( "forceRefresh" ) ;
64- const finalResponse = response . redirect ( redirectUrl ) ;
65- finalResponse . headers . set ( "x-current-path" , redirectUrl . pathname ) ;
66- // @ts -expect-error TS(2345) It complains about tokens being null although we check for that in the previous if condition
67- attachTokensToResponse ( finalResponse , tokens ) ;
68- logDebugMessage ( "Attached new tokens to response" ) ;
69- return finalResponse ;
70- } catch ( err ) {
71- logDebugMessage ( "Error refreshing session" ) ;
72- logDebugMessage ( err as unknown as string ) ;
73- return redirectToAuthPage ( request , response ) ;
74- }
50+ const redirectUrl = new URL ( request . url ) ;
51+ redirectUrl . searchParams . delete ( "forceRefresh" ) ;
52+ const finalResponse = response . redirect ( redirectUrl ) ;
53+ finalResponse . headers . set ( "x-current-path" , redirectUrl . pathname ) ;
54+ // @ts -expect-error TS(2345) It complains about tokens being null although we check for that in the previous if condition
55+ attachTokensToResponse ( finalResponse , tokens ) ;
56+ logDebugMessage ( "Attached new tokens to response" ) ;
57+ return finalResponse ;
58+ } catch ( err ) {
59+ logDebugMessage ( "Error refreshing session" ) ;
60+ console . error ( err ) ;
61+ logDebugMessage ( err as unknown as string ) ;
62+ return redirectToAuthPage ( request , response ) ;
7563 }
7664}
7765
78- export const init = SuperTokensNextjsEdgeAPIWrapper . init ;
79- export const refreshSession = SuperTokensNextjsEdgeAPIWrapper . refreshSession ;
80- export const superTokensSSRMiddleware = SuperTokensNextjsEdgeAPIWrapper . middleware ;
81-
82- function getRefreshApiURL ( ) : string {
83- const appInfo = SuperTokensNextjsEdgeAPIWrapper . getConfigOrThrow ( ) . appInfo ;
84- return sanitizeUrl ( `${ appInfo . apiDomain } /${ appInfo . apiBasePath } /session/refresh` ) ;
85- }
86-
8766function redirectToAuthPage ( request : NextRequest , response : NextResponse ) : NextResponse {
88- const appInfo = SuperTokensNextjsEdgeAPIWrapper . getConfigOrThrow ( ) . appInfo ;
89- const authPagePath = appInfo . websiteBasePath || "/auth" ;
67+ const authPagePath = AppInfo . websiteBasePath || "/auth" ;
9068 const redirectUrl = new URL ( authPagePath , request . url ) ;
9169 logDebugMessage ( `Redirecting to: ${ redirectUrl } ` ) ;
9270 return response . redirect ( redirectUrl ) ;
@@ -95,7 +73,9 @@ function redirectToAuthPage(request: NextRequest, response: NextResponse): NextR
9573async function fetchNewTokens (
9674 currentRefreshToken : string
9775) : Promise < { accessToken : string | null ; refreshToken : string | null ; frontToken : string | null } > {
98- const refreshResponse = await fetch ( getRefreshApiURL ( ) , {
76+ const refreshApiURL = new URL ( `${ AppInfo . apiBasePath } /session/refresh` , AppInfo . apiDomain ) ;
77+ console . log ( refreshApiURL . pathname ) ;
78+ const refreshResponse = await fetch ( refreshApiURL , {
9979 method : "POST" ,
10080 headers : {
10181 "Content-Type" : "application/json" ,
@@ -145,9 +125,6 @@ function attachTokensToResponse(
145125 response . cookies . set ( FRONT_TOKEN_COOKIE_NAME , tokens . frontToken ) ;
146126}
147127
148- function sanitizeUrl ( url : string ) {
149- return url . replace ( / ( [ ^ : ] \/ ) \/ + / g, "$1" ) ;
150- }
151128export function getCookieValue ( header : string , name : string ) : string | null {
152129 const match = header . match ( new RegExp ( `${ name } =([^;]+)` ) ) ;
153130 return match ? match [ 1 ] : null ;
0 commit comments