@descope/nextjs-sdk 0.15.55 → 0.15.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -48,26 +48,21 @@ const isPublicRoute = (req, options) => {
48
48
  // If no routes are provided, all routes are private
49
49
  return isDefaultPublicRoute;
50
50
  };
51
- const addSessionToHeadersIfExists = (headers, session) => {
52
- if (session) {
53
- const requestHeaders = new Headers(headers);
54
- requestHeaders.set(constants.DESCOPE_SESSION_HEADER, Buffer.from(JSON.stringify(session)).toString('base64'));
55
- return requestHeaders;
56
- }
57
- return headers;
51
+ const removeSessionHeader = (headers) => {
52
+ const requestHeaders = new Headers(headers);
53
+ requestHeaders.delete(constants.DESCOPE_SESSION_HEADER);
54
+ return requestHeaders;
58
55
  };
59
56
  // returns a Middleware that checks if the user is authenticated
60
57
  // if the user is not authenticated, it redirects to the redirectUrl
61
- // if the user is authenticated, it adds the session to the headers
62
58
  const createAuthMiddleware = (options = {}) => async (req) => {
63
59
  logger.setLogger(options.logLevel);
64
60
  logger.logger.debug('[Auth middleware] Starts');
65
61
  const sessionJwt = getSessionJwt(req, options);
66
62
  // check if the user is authenticated
67
- let session;
68
63
  let validToken = false;
69
64
  try {
70
- session = await sdk.getGlobalSdk({
65
+ await sdk.getGlobalSdk({
71
66
  projectId: options.projectId,
72
67
  baseUrl: options.baseUrl
73
68
  }).validateJwt(sessionJwt);
@@ -109,8 +104,7 @@ const createAuthMiddleware = (options = {}) => async (req) => {
109
104
  }
110
105
  }
111
106
  logger.logger.debug('[Auth middleware] finishes');
112
- // Add the session to the request headers and continue
113
- const headers = addSessionToHeadersIfExists(req.headers, session);
107
+ const headers = removeSessionHeader(req.headers);
114
108
  return server_js.NextResponse.next({
115
109
  request: {
116
110
  headers
@@ -1 +1 @@
1
- {"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport descopeSdk from '@descope/node-sdk';\nimport type { AuthenticationInfo } from '@descope/node-sdk';\nimport { DEFAULT_PUBLIC_ROUTES, DESCOPE_SESSION_HEADER } from './constants';\nimport { getGlobalSdk } from './sdk';\nimport { mergeSearchParams } from './utils';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_BASE_URL\n\tbaseUrl?: string;\n\n\t// The URL to redirect to if the user is not authenticated\n\t// Defaults to process.env.SIGN_IN_ROUTE or '/sign-in' if not provided\n\t// NOTE: In case it contains query parameters that exist in the original URL, they will override the original query parameters. e.g. if the original URL is /page?param1=1&param2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3&param2=2\n\tredirectUrl?: string;\n\n\t// An array of public routes that do not require authentication\n\t// In addition to the default public routes:\n\t// - process.env.SIGN_IN_ROUTE or /sign-in if not provided\n\t// - process.env.SIGN_UP_ROUTE or /sign-up if not provided\n\tpublicRoutes?: string[];\n\n\t// An array of private routes that require authentication\n\t// If privateRoutes is defined, routes not listed in this array will default to public routes\n\tprivateRoutes?: string[];\n\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\t// Used to refresh the session when the JWT expires\n\trefreshTokenCookieName?: string;\n};\n\nconst getSessionJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tlet jwt = req.headers?.get('Authorization')?.split(' ')[1];\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\n\tjwt = req.cookies?.get(\n\t\toptions?.sessionCookieName || descopeSdk.SessionTokenCookieName\n\t)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\n};\n\nconst getRefreshJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tconst refreshJwt = req.cookies?.get(\n\t\toptions?.refreshTokenCookieName || 'DSR'\n\t)?.value;\n\treturn refreshJwt;\n};\n\nconst matchWildcardRoute = (route: string, path: string) => {\n\tlet regexPattern = route.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n\t// Convert wildcard (*) to match path segments only\n\tregexPattern = regexPattern.replace(/\\*/g, '[^/]*');\n\tconst regex = new RegExp(`^${regexPattern}$`);\n\n\treturn regex.test(path);\n};\n\nconst isPublicRoute = (req: NextRequest, options: MiddlewareOptions) => {\n\t// Ensure publicRoutes and privateRoutes are arrays, defaulting to empty arrays if not defined\n\tconst { publicRoutes = [], privateRoutes = [] } = options;\n\tconst { pathname } = req.nextUrl;\n\n\tconst isDefaultPublicRoute = Object.values(DEFAULT_PUBLIC_ROUTES).includes(\n\t\tpathname\n\t);\n\n\tif (publicRoutes.length > 0) {\n\t\tif (privateRoutes.length > 0) {\n\t\t\tlogger.warn(\n\t\t\t\t'Both publicRoutes and privateRoutes are defined. Ignoring privateRoutes.'\n\t\t\t);\n\t\t}\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\tpublicRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\tif (privateRoutes.length > 0) {\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\t!privateRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\t// If no routes are provided, all routes are private\n\treturn isDefaultPublicRoute;\n};\n\nconst addSessionToHeadersIfExists = (\n\theaders: Headers,\n\tsession: AuthenticationInfo | undefined\n): Headers => {\n\tif (session) {\n\t\tconst requestHeaders = new Headers(headers);\n\t\trequestHeaders.set(\n\t\t\tDESCOPE_SESSION_HEADER,\n\t\t\tBuffer.from(JSON.stringify(session)).toString('base64')\n\t\t);\n\t\treturn requestHeaders;\n\t}\n\treturn headers;\n};\n\n// returns a Middleware that checks if the user is authenticated\n// if the user is not authenticated, it redirects to the redirectUrl\n// if the user is authenticated, it adds the session to the headers\nconst createAuthMiddleware =\n\t(options: MiddlewareOptions = {}) =>\n\tasync (req: NextRequest) => {\n\t\tsetLogger(options.logLevel);\n\t\tlogger.debug('[Auth middleware] Starts');\n\n\t\tconst sessionJwt = getSessionJwt(req, options);\n\n\t\t// check if the user is authenticated\n\t\tlet session: AuthenticationInfo | undefined;\n\t\tlet validToken = false;\n\t\ttry {\n\t\t\tsession = await getGlobalSdk({\n\t\t\t\tprojectId: options.projectId,\n\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t}).validateJwt(sessionJwt);\n\t\t\tvalidToken = true;\n\t\t\tlogger.debug('[Auth middleware] Session JWT is valid');\n\t\t} catch (err) {\n\t\t\tlogger.debug('[Auth middleware] Failed to validate session JWT', err);\n\n\t\t\t// Try to validate the refresh token instead\n\t\t\tconst refreshJwt = getRefreshJwt(req, options);\n\t\t\tif (refreshJwt) {\n\t\t\t\tlogger.debug('[Auth middleware] Attempting to validate refresh token');\n\t\t\t\ttry {\n\t\t\t\t\tawait getGlobalSdk({\n\t\t\t\t\t\tprojectId: options.projectId,\n\t\t\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t\t\t}).validateJwt(refreshJwt);\n\n\t\t\t\t\tlogger.debug('[Auth middleware] Refresh token is valid');\n\t\t\t\t\tvalidToken = true;\n\t\t\t\t} catch (refreshErr) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t'[Auth middleware] Refresh token validation failed',\n\t\t\t\t\t\trefreshErr\n\t\t\t\t\t);\n\t\t\t\t\t// Refresh token validation failed, continue to redirect logic below\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we don't have a valid session or refresh token and this is a private route, redirect\n\t\t\tif (!validToken && !isPublicRoute(req, options)) {\n\t\t\t\tconst redirectUrl = options.redirectUrl || DEFAULT_PUBLIC_ROUTES.signIn;\n\t\t\t\tconst url = req.nextUrl.clone();\n\t\t\t\t// Create a URL object for redirectUrl. 'http://example.com' is just a placeholder.\n\t\t\t\tconst parsedRedirectUrl = new URL(redirectUrl, 'http://example.com');\n\t\t\t\turl.pathname = parsedRedirectUrl.pathname;\n\n\t\t\t\tconst searchParams = mergeSearchParams(\n\t\t\t\t\turl.search,\n\t\t\t\t\tparsedRedirectUrl.search\n\t\t\t\t);\n\t\t\t\tif (searchParams) {\n\t\t\t\t\turl.search = searchParams;\n\t\t\t\t}\n\t\t\t\tlogger.debug(`[Auth middleware] Redirecting to ${redirectUrl}`);\n\t\t\t\treturn NextResponse.redirect(url);\n\t\t\t}\n\t\t}\n\n\t\tlogger.debug('[Auth middleware] finishes');\n\n\t\t// Add the session to the request headers and continue\n\t\tconst headers = addSessionToHeadersIfExists(req.headers, session);\n\t\treturn NextResponse.next({\n\t\t\trequest: {\n\t\t\t\theaders\n\t\t\t}\n\t\t});\n\t};\n\nexport default createAuthMiddleware;\n"],"names":["DEFAULT_PUBLIC_ROUTES","logger","DESCOPE_SESSION_HEADER","setLogger","getGlobalSdk","mergeSearchParams","NextResponse"],"mappings":"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"}
1
+ {"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport descopeSdk from '@descope/node-sdk';\nimport { DEFAULT_PUBLIC_ROUTES, DESCOPE_SESSION_HEADER } from './constants';\nimport { getGlobalSdk } from './sdk';\nimport { mergeSearchParams } from './utils';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_BASE_URL\n\tbaseUrl?: string;\n\n\t// The URL to redirect to if the user is not authenticated\n\t// Defaults to process.env.SIGN_IN_ROUTE or '/sign-in' if not provided\n\t// NOTE: In case it contains query parameters that exist in the original URL, they will override the original query parameters. e.g. if the original URL is /page?param1=1&param2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3&param2=2\n\tredirectUrl?: string;\n\n\t// An array of public routes that do not require authentication\n\t// In addition to the default public routes:\n\t// - process.env.SIGN_IN_ROUTE or /sign-in if not provided\n\t// - process.env.SIGN_UP_ROUTE or /sign-up if not provided\n\tpublicRoutes?: string[];\n\n\t// An array of private routes that require authentication\n\t// If privateRoutes is defined, routes not listed in this array will default to public routes\n\tprivateRoutes?: string[];\n\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\t// Used to refresh the session when the JWT expires\n\trefreshTokenCookieName?: string;\n};\n\nconst getSessionJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tlet jwt = req.headers?.get('Authorization')?.split(' ')[1];\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\n\tjwt = req.cookies?.get(\n\t\toptions?.sessionCookieName || descopeSdk.SessionTokenCookieName\n\t)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\n};\n\nconst getRefreshJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tconst refreshJwt = req.cookies?.get(\n\t\toptions?.refreshTokenCookieName || 'DSR'\n\t)?.value;\n\treturn refreshJwt;\n};\n\nconst matchWildcardRoute = (route: string, path: string) => {\n\tlet regexPattern = route.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n\t// Convert wildcard (*) to match path segments only\n\tregexPattern = regexPattern.replace(/\\*/g, '[^/]*');\n\tconst regex = new RegExp(`^${regexPattern}$`);\n\n\treturn regex.test(path);\n};\n\nconst isPublicRoute = (req: NextRequest, options: MiddlewareOptions) => {\n\t// Ensure publicRoutes and privateRoutes are arrays, defaulting to empty arrays if not defined\n\tconst { publicRoutes = [], privateRoutes = [] } = options;\n\tconst { pathname } = req.nextUrl;\n\n\tconst isDefaultPublicRoute = Object.values(DEFAULT_PUBLIC_ROUTES).includes(\n\t\tpathname\n\t);\n\n\tif (publicRoutes.length > 0) {\n\t\tif (privateRoutes.length > 0) {\n\t\t\tlogger.warn(\n\t\t\t\t'Both publicRoutes and privateRoutes are defined. Ignoring privateRoutes.'\n\t\t\t);\n\t\t}\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\tpublicRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\tif (privateRoutes.length > 0) {\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\t!privateRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\t// If no routes are provided, all routes are private\n\treturn isDefaultPublicRoute;\n};\n\nconst removeSessionHeader = (headers: Headers): Headers => {\n\tconst requestHeaders = new Headers(headers);\n\trequestHeaders.delete(DESCOPE_SESSION_HEADER);\n\treturn requestHeaders;\n};\n\n// returns a Middleware that checks if the user is authenticated\n// if the user is not authenticated, it redirects to the redirectUrl\nconst createAuthMiddleware =\n\t(options: MiddlewareOptions = {}) =>\n\tasync (req: NextRequest) => {\n\t\tsetLogger(options.logLevel);\n\t\tlogger.debug('[Auth middleware] Starts');\n\n\t\tconst sessionJwt = getSessionJwt(req, options);\n\n\t\t// check if the user is authenticated\n\t\tlet validToken = false;\n\t\ttry {\n\t\t\tawait getGlobalSdk({\n\t\t\t\tprojectId: options.projectId,\n\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t}).validateJwt(sessionJwt);\n\t\t\tvalidToken = true;\n\t\t\tlogger.debug('[Auth middleware] Session JWT is valid');\n\t\t} catch (err) {\n\t\t\tlogger.debug('[Auth middleware] Failed to validate session JWT', err);\n\n\t\t\t// Try to validate the refresh token instead\n\t\t\tconst refreshJwt = getRefreshJwt(req, options);\n\t\t\tif (refreshJwt) {\n\t\t\t\tlogger.debug('[Auth middleware] Attempting to validate refresh token');\n\t\t\t\ttry {\n\t\t\t\t\tawait getGlobalSdk({\n\t\t\t\t\t\tprojectId: options.projectId,\n\t\t\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t\t\t}).validateJwt(refreshJwt);\n\n\t\t\t\t\tlogger.debug('[Auth middleware] Refresh token is valid');\n\t\t\t\t\tvalidToken = true;\n\t\t\t\t} catch (refreshErr) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t'[Auth middleware] Refresh token validation failed',\n\t\t\t\t\t\trefreshErr\n\t\t\t\t\t);\n\t\t\t\t\t// Refresh token validation failed, continue to redirect logic below\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we don't have a valid session or refresh token and this is a private route, redirect\n\t\t\tif (!validToken && !isPublicRoute(req, options)) {\n\t\t\t\tconst redirectUrl = options.redirectUrl || DEFAULT_PUBLIC_ROUTES.signIn;\n\t\t\t\tconst url = req.nextUrl.clone();\n\t\t\t\t// Create a URL object for redirectUrl. 'http://example.com' is just a placeholder.\n\t\t\t\tconst parsedRedirectUrl = new URL(redirectUrl, 'http://example.com');\n\t\t\t\turl.pathname = parsedRedirectUrl.pathname;\n\n\t\t\t\tconst searchParams = mergeSearchParams(\n\t\t\t\t\turl.search,\n\t\t\t\t\tparsedRedirectUrl.search\n\t\t\t\t);\n\t\t\t\tif (searchParams) {\n\t\t\t\t\turl.search = searchParams;\n\t\t\t\t}\n\t\t\t\tlogger.debug(`[Auth middleware] Redirecting to ${redirectUrl}`);\n\t\t\t\treturn NextResponse.redirect(url);\n\t\t\t}\n\t\t}\n\n\t\tlogger.debug('[Auth middleware] finishes');\n\n\t\tconst headers = removeSessionHeader(req.headers);\n\t\treturn NextResponse.next({\n\t\t\trequest: {\n\t\t\t\theaders\n\t\t\t}\n\t\t});\n\t};\n\nexport default createAuthMiddleware;\n"],"names":["DEFAULT_PUBLIC_ROUTES","logger","DESCOPE_SESSION_HEADER","setLogger","getGlobalSdk","mergeSearchParams","NextResponse"],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  const DESCOPE_SESSION_HEADER = 'x-descope-session';
4
4
  const baseHeaders = {
5
5
  'x-descope-sdk-name': 'nextjs',
6
- 'x-descope-sdk-version': "0.15.55"
6
+ 'x-descope-sdk-version': "0.15.57"
7
7
  };
8
8
  const DEFAULT_PUBLIC_ROUTES = {
9
9
  signIn: process.env.SIGN_IN_ROUTE || '/sign-in',
@@ -2,59 +2,52 @@
2
2
 
3
3
  var descopeSdk = require('@descope/node-sdk');
4
4
  var headers_js = require('next/headers.js');
5
- var constants = require('./constants.js');
6
5
  var sdk = require('./sdk.js');
7
6
  var logger = require('./logger.js');
8
7
 
9
- const extractSession = (descopeSession) => {
10
- if (!descopeSession) {
11
- return undefined;
12
- }
13
- try {
14
- const authInfo = JSON.parse(Buffer.from(descopeSession, 'base64').toString());
15
- return authInfo;
8
+ const getSessionCookieName = (config) => config?.sessionCookieName || descopeSdk.SessionTokenCookieName;
9
+ // tries to validate the Authorization header,
10
+ // if it doesn't exist or is invalid, it will attempt to validate the session cookie
11
+ const getSessionFromAuthorizationOrCookie = async (authorization, cookieJwt, config) => {
12
+ const sessionJwt = authorization?.split(' ')[1];
13
+ if (sessionJwt) {
14
+ try {
15
+ const sdk$1 = sdk.getGlobalSdk(config);
16
+ return await sdk$1.validateJwt(sessionJwt);
17
+ }
18
+ catch (err) {
19
+ logger.logger.debug('Error validating session from Authorization header', err);
20
+ }
16
21
  }
17
- catch (err) {
22
+ logger.logger.debug('attempting to get session from cookie');
23
+ if (!cookieJwt) {
24
+ logger.logger.debug('Session cookie not found');
18
25
  return undefined;
19
26
  }
20
- };
21
- const getSessionFromCookie = async (config) => {
22
- logger.logger.debug('attempting to get session from cookie');
23
27
  try {
24
- const sessionCookie = (await headers_js.cookies()).get(config?.sessionCookieName || descopeSdk.SessionTokenCookieName);
25
- if (!sessionCookie?.value) {
26
- logger.logger.debug('Session cookie not found');
27
- return undefined;
28
- }
29
28
  const sdk$1 = sdk.getGlobalSdk(config);
30
- return await sdk$1.validateJwt(sessionCookie.value);
29
+ return await sdk$1.validateJwt(cookieJwt);
31
30
  }
32
31
  catch (err) {
33
32
  logger.logger.debug('Error getting session from cookie', err);
34
33
  return undefined;
35
34
  }
36
35
  };
37
- // tries to extract the session header,
38
- // if it doesn't exist, it will attempt to get the session from the cookie
39
- const extractOrGetSession = async (sessionHeader, config) => {
40
- const session = extractSession(sessionHeader);
41
- if (session) {
42
- return session;
43
- }
44
- return getSessionFromCookie(config);
45
- };
46
- // returns the session token if it exists in the headers
36
+ // returns the session token if it exists in the Authorization header or cookie
47
37
  const session = async (config) => {
48
38
  logger.setLogger(config?.logLevel);
49
- // first attempt to get the session from the headers
50
39
  const reqHeaders = await headers_js.headers();
51
- const sessionHeader = reqHeaders.get(constants.DESCOPE_SESSION_HEADER);
52
- return extractOrGetSession(sessionHeader, config);
40
+ const cookieJwt = (await headers_js.cookies()).get(getSessionCookieName(config))?.value;
41
+ return getSessionFromAuthorizationOrCookie(reqHeaders.get('Authorization'), cookieJwt, config);
53
42
  };
54
- // returns the session token if it exists in the request headers
43
+ // returns the session token if it exists in the request Authorization header or cookie
55
44
  const getSession = async (req, config) => {
56
45
  logger.setLogger(config?.logLevel);
57
- return extractOrGetSession(req.headers[constants.DESCOPE_SESSION_HEADER.toLowerCase()], config);
46
+ const { authorization } = req.headers;
47
+ return getSessionFromAuthorizationOrCookie(typeof authorization === 'string' ? authorization : undefined,
48
+ // Pages Router request - next/headers cookies() is not available here,
49
+ // so the session cookie must be read directly from the request
50
+ req.cookies?.[getSessionCookieName(config)], config);
58
51
  };
59
52
 
60
53
  exports.getSession = getSession;
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["import descopeSdk, { AuthenticationInfo } from '@descope/node-sdk';\nimport { NextApiRequest } from 'next';\nimport { cookies, headers } from 'next/headers';\nimport { DESCOPE_SESSION_HEADER } from './constants';\nimport { getGlobalSdk, CreateSdkParams } from './sdk';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype SessionConfig = CreateSdkParams & {\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\trefreshTokenCookieName?: string;\n};\n\nconst extractSession = (\n\tdescopeSession?: string\n): AuthenticationInfo | undefined => {\n\tif (!descopeSession) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst authInfo = JSON.parse(\n\t\t\tBuffer.from(descopeSession, 'base64').toString()\n\t\t) as AuthenticationInfo;\n\t\treturn authInfo;\n\t} catch (err) {\n\t\treturn undefined;\n\t}\n};\n\nconst getSessionFromCookie = async (\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tlogger.debug('attempting to get session from cookie');\n\ttry {\n\t\tconst sessionCookie = (await cookies()).get(\n\t\t\tconfig?.sessionCookieName || descopeSdk.SessionTokenCookieName\n\t\t);\n\t\tif (!sessionCookie?.value) {\n\t\t\tlogger.debug('Session cookie not found');\n\t\t\treturn undefined;\n\t\t}\n\t\tconst sdk = getGlobalSdk(config);\n\t\treturn await sdk.validateJwt(sessionCookie.value);\n\t} catch (err) {\n\t\tlogger.debug('Error getting session from cookie', err);\n\t\treturn undefined;\n\t}\n};\n\n// tries to extract the session header,\n// if it doesn't exist, it will attempt to get the session from the cookie\nconst extractOrGetSession = async (\n\tsessionHeader?: string,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tconst session = extractSession(sessionHeader);\n\tif (session) {\n\t\treturn session;\n\t}\n\n\treturn getSessionFromCookie(config);\n};\n\n// returns the session token if it exists in the headers\nexport const session = async (\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\t// first attempt to get the session from the headers\n\tconst reqHeaders = await headers();\n\tconst sessionHeader = reqHeaders.get(DESCOPE_SESSION_HEADER);\n\treturn extractOrGetSession(sessionHeader, config);\n};\n\n// returns the session token if it exists in the request headers\nexport const getSession = async (\n\treq: NextApiRequest,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\treturn extractOrGetSession(\n\t\treq.headers[DESCOPE_SESSION_HEADER.toLowerCase()] as string,\n\t\tconfig\n\t);\n};\n"],"names":["logger","cookies","sdk","getGlobalSdk","setLogger","headers","DESCOPE_SESSION_HEADER"],"mappings":";;;;;;;;AAuBA,MAAM,cAAc,GAAG,CACtB,cAAuB,KACY;IACnC,IAAI,CAAC,cAAc,EAAE;AACpB,QAAA,OAAO,SAAS,CAAC;KACjB;AACD,IAAA,IAAI;AACH,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAC1B,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAC1B,CAAC;AACxB,QAAA,OAAO,QAAQ,CAAC;KAChB;IAAC,OAAO,GAAG,EAAE;AACb,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,OAC5B,MAAsB,KACsB;AAC5C,IAAAA,aAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;AACtD,IAAA,IAAI;AACH,QAAA,MAAM,aAAa,GAAG,CAAC,MAAMC,kBAAO,EAAE,EAAE,GAAG,CAC1C,MAAM,EAAE,iBAAiB,IAAI,UAAU,CAAC,sBAAsB,CAC9D,CAAC;AACF,QAAA,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE;AAC1B,YAAAD,aAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AACzC,YAAA,OAAO,SAAS,CAAC;SACjB;AACD,QAAA,MAAME,KAAG,GAAGC,gBAAY,CAAC,MAAM,CAAC,CAAC;QACjC,OAAO,MAAMD,KAAG,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;KAClD;IAAC,OAAO,GAAG,EAAE;AACb,QAAAF,aAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;AACvD,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF;AACA;AACA,MAAM,mBAAmB,GAAG,OAC3B,aAAsB,EACtB,MAAsB,KACsB;AAC5C,IAAA,MAAM,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IAC9C,IAAI,OAAO,EAAE;AACZ,QAAA,OAAO,OAAO,CAAC;KACf;AAED,IAAA,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF;MACa,OAAO,GAAG,OACtB,MAAsB,KACsB;AAC5C,IAAAI,gBAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;;AAE5B,IAAA,MAAM,UAAU,GAAG,MAAMC,kBAAO,EAAE,CAAC;IACnC,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,CAACC,gCAAsB,CAAC,CAAC;AAC7D,IAAA,OAAO,mBAAmB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AACnD,EAAE;AAEF;AACa,MAAA,UAAU,GAAG,OACzB,GAAmB,EACnB,MAAsB,KACsB;AAC5C,IAAAF,gBAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC5B,IAAA,OAAO,mBAAmB,CACzB,GAAG,CAAC,OAAO,CAACE,gCAAsB,CAAC,WAAW,EAAE,CAAW,EAC3D,MAAM,CACN,CAAC;AACH;;;;;"}
1
+ {"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["import descopeSdk, { AuthenticationInfo } from '@descope/node-sdk';\nimport { NextApiRequest } from 'next';\nimport { cookies, headers } from 'next/headers';\nimport { getGlobalSdk, CreateSdkParams } from './sdk';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype SessionConfig = CreateSdkParams & {\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\trefreshTokenCookieName?: string;\n};\n\nconst getSessionCookieName = (config?: SessionConfig) =>\n\tconfig?.sessionCookieName || descopeSdk.SessionTokenCookieName;\n\n// tries to validate the Authorization header,\n// if it doesn't exist or is invalid, it will attempt to validate the session cookie\nconst getSessionFromAuthorizationOrCookie = async (\n\tauthorization: string | null | undefined,\n\tcookieJwt: string | undefined,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tconst sessionJwt = authorization?.split(' ')[1];\n\tif (sessionJwt) {\n\t\ttry {\n\t\t\tconst sdk = getGlobalSdk(config);\n\t\t\treturn await sdk.validateJwt(sessionJwt);\n\t\t} catch (err) {\n\t\t\tlogger.debug('Error validating session from Authorization header', err);\n\t\t}\n\t}\n\n\tlogger.debug('attempting to get session from cookie');\n\tif (!cookieJwt) {\n\t\tlogger.debug('Session cookie not found');\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst sdk = getGlobalSdk(config);\n\t\treturn await sdk.validateJwt(cookieJwt);\n\t} catch (err) {\n\t\tlogger.debug('Error getting session from cookie', err);\n\t\treturn undefined;\n\t}\n};\n\n// returns the session token if it exists in the Authorization header or cookie\nexport const session = async (\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\tconst reqHeaders = await headers();\n\tconst cookieJwt = (await cookies()).get(getSessionCookieName(config))?.value;\n\treturn getSessionFromAuthorizationOrCookie(\n\t\treqHeaders.get('Authorization'),\n\t\tcookieJwt,\n\t\tconfig\n\t);\n};\n\n// returns the session token if it exists in the request Authorization header or cookie\nexport const getSession = async (\n\treq: NextApiRequest,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\tconst { authorization } = req.headers;\n\treturn getSessionFromAuthorizationOrCookie(\n\t\ttypeof authorization === 'string' ? authorization : undefined,\n\t\t// Pages Router request - next/headers cookies() is not available here,\n\t\t// so the session cookie must be read directly from the request\n\t\treq.cookies?.[getSessionCookieName(config)],\n\t\tconfig\n\t);\n};\n"],"names":["sdk","getGlobalSdk","logger","setLogger","headers","cookies"],"mappings":";;;;;;;AAsBA,MAAM,oBAAoB,GAAG,CAAC,MAAsB,KACnD,MAAM,EAAE,iBAAiB,IAAI,UAAU,CAAC,sBAAsB,CAAC;AAEhE;AACA;AACA,MAAM,mCAAmC,GAAG,OAC3C,aAAwC,EACxC,SAA6B,EAC7B,MAAsB,KACsB;IAC5C,MAAM,UAAU,GAAG,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,UAAU,EAAE;AACf,QAAA,IAAI;AACH,YAAA,MAAMA,KAAG,GAAGC,gBAAY,CAAC,MAAM,CAAC,CAAC;AACjC,YAAA,OAAO,MAAMD,KAAG,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;SACzC;QAAC,OAAO,GAAG,EAAE;AACb,YAAAE,aAAM,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,CAAC,CAAC;SACxE;KACD;AAED,IAAAA,aAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACtD,IAAI,CAAC,SAAS,EAAE;AACf,QAAAA,aAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AACzC,QAAA,OAAO,SAAS,CAAC;KACjB;AACD,IAAA,IAAI;AACH,QAAA,MAAMF,KAAG,GAAGC,gBAAY,CAAC,MAAM,CAAC,CAAC;AACjC,QAAA,OAAO,MAAMD,KAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;KACxC;IAAC,OAAO,GAAG,EAAE;AACb,QAAAE,aAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;AACvD,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF;MACa,OAAO,GAAG,OACtB,MAAsB,KACsB;AAC5C,IAAAC,gBAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC5B,IAAA,MAAM,UAAU,GAAG,MAAMC,kBAAO,EAAE,CAAC;AACnC,IAAA,MAAM,SAAS,GAAG,CAAC,MAAMC,kBAAO,EAAE,EAAE,GAAG,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC;AAC7E,IAAA,OAAO,mCAAmC,CACzC,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,EAC/B,SAAS,EACT,MAAM,CACN,CAAC;AACH,EAAE;AAEF;AACa,MAAA,UAAU,GAAG,OACzB,GAAmB,EACnB,MAAsB,KACsB;AAC5C,IAAAF,gBAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC5B,IAAA,MAAM,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;AACtC,IAAA,OAAO,mCAAmC,CACzC,OAAO,aAAa,KAAK,QAAQ,GAAG,aAAa,GAAG,SAAS;;;AAG7D,IAAA,GAAG,CAAC,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,EAC3C,MAAM,CACN,CAAC;AACH;;;;;"}
@@ -3,7 +3,7 @@
3
3
  // eslint-disable-next-line import/prefer-default-export
4
4
  const baseHeaders = {
5
5
  'x-descope-sdk-name': 'nextjs',
6
- 'x-descope-sdk-version': "0.15.55"
6
+ 'x-descope-sdk-version': "0.15.57"
7
7
  };
8
8
 
9
9
  exports.baseHeaders = baseHeaders;
@@ -46,26 +46,21 @@ const isPublicRoute = (req, options) => {
46
46
  // If no routes are provided, all routes are private
47
47
  return isDefaultPublicRoute;
48
48
  };
49
- const addSessionToHeadersIfExists = (headers, session) => {
50
- if (session) {
51
- const requestHeaders = new Headers(headers);
52
- requestHeaders.set(DESCOPE_SESSION_HEADER, Buffer.from(JSON.stringify(session)).toString('base64'));
53
- return requestHeaders;
54
- }
55
- return headers;
49
+ const removeSessionHeader = (headers) => {
50
+ const requestHeaders = new Headers(headers);
51
+ requestHeaders.delete(DESCOPE_SESSION_HEADER);
52
+ return requestHeaders;
56
53
  };
57
54
  // returns a Middleware that checks if the user is authenticated
58
55
  // if the user is not authenticated, it redirects to the redirectUrl
59
- // if the user is authenticated, it adds the session to the headers
60
56
  const createAuthMiddleware = (options = {}) => async (req) => {
61
57
  setLogger(options.logLevel);
62
58
  logger.debug('[Auth middleware] Starts');
63
59
  const sessionJwt = getSessionJwt(req, options);
64
60
  // check if the user is authenticated
65
- let session;
66
61
  let validToken = false;
67
62
  try {
68
- session = await getGlobalSdk({
63
+ await getGlobalSdk({
69
64
  projectId: options.projectId,
70
65
  baseUrl: options.baseUrl
71
66
  }).validateJwt(sessionJwt);
@@ -107,8 +102,7 @@ const createAuthMiddleware = (options = {}) => async (req) => {
107
102
  }
108
103
  }
109
104
  logger.debug('[Auth middleware] finishes');
110
- // Add the session to the request headers and continue
111
- const headers = addSessionToHeadersIfExists(req.headers, session);
105
+ const headers = removeSessionHeader(req.headers);
112
106
  return NextResponse.next({
113
107
  request: {
114
108
  headers
@@ -1 +1 @@
1
- {"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport descopeSdk from '@descope/node-sdk';\nimport type { AuthenticationInfo } from '@descope/node-sdk';\nimport { DEFAULT_PUBLIC_ROUTES, DESCOPE_SESSION_HEADER } from './constants';\nimport { getGlobalSdk } from './sdk';\nimport { mergeSearchParams } from './utils';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_BASE_URL\n\tbaseUrl?: string;\n\n\t// The URL to redirect to if the user is not authenticated\n\t// Defaults to process.env.SIGN_IN_ROUTE or '/sign-in' if not provided\n\t// NOTE: In case it contains query parameters that exist in the original URL, they will override the original query parameters. e.g. if the original URL is /page?param1=1&param2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3&param2=2\n\tredirectUrl?: string;\n\n\t// An array of public routes that do not require authentication\n\t// In addition to the default public routes:\n\t// - process.env.SIGN_IN_ROUTE or /sign-in if not provided\n\t// - process.env.SIGN_UP_ROUTE or /sign-up if not provided\n\tpublicRoutes?: string[];\n\n\t// An array of private routes that require authentication\n\t// If privateRoutes is defined, routes not listed in this array will default to public routes\n\tprivateRoutes?: string[];\n\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\t// Used to refresh the session when the JWT expires\n\trefreshTokenCookieName?: string;\n};\n\nconst getSessionJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tlet jwt = req.headers?.get('Authorization')?.split(' ')[1];\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\n\tjwt = req.cookies?.get(\n\t\toptions?.sessionCookieName || descopeSdk.SessionTokenCookieName\n\t)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\n};\n\nconst getRefreshJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tconst refreshJwt = req.cookies?.get(\n\t\toptions?.refreshTokenCookieName || 'DSR'\n\t)?.value;\n\treturn refreshJwt;\n};\n\nconst matchWildcardRoute = (route: string, path: string) => {\n\tlet regexPattern = route.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n\t// Convert wildcard (*) to match path segments only\n\tregexPattern = regexPattern.replace(/\\*/g, '[^/]*');\n\tconst regex = new RegExp(`^${regexPattern}$`);\n\n\treturn regex.test(path);\n};\n\nconst isPublicRoute = (req: NextRequest, options: MiddlewareOptions) => {\n\t// Ensure publicRoutes and privateRoutes are arrays, defaulting to empty arrays if not defined\n\tconst { publicRoutes = [], privateRoutes = [] } = options;\n\tconst { pathname } = req.nextUrl;\n\n\tconst isDefaultPublicRoute = Object.values(DEFAULT_PUBLIC_ROUTES).includes(\n\t\tpathname\n\t);\n\n\tif (publicRoutes.length > 0) {\n\t\tif (privateRoutes.length > 0) {\n\t\t\tlogger.warn(\n\t\t\t\t'Both publicRoutes and privateRoutes are defined. Ignoring privateRoutes.'\n\t\t\t);\n\t\t}\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\tpublicRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\tif (privateRoutes.length > 0) {\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\t!privateRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\t// If no routes are provided, all routes are private\n\treturn isDefaultPublicRoute;\n};\n\nconst addSessionToHeadersIfExists = (\n\theaders: Headers,\n\tsession: AuthenticationInfo | undefined\n): Headers => {\n\tif (session) {\n\t\tconst requestHeaders = new Headers(headers);\n\t\trequestHeaders.set(\n\t\t\tDESCOPE_SESSION_HEADER,\n\t\t\tBuffer.from(JSON.stringify(session)).toString('base64')\n\t\t);\n\t\treturn requestHeaders;\n\t}\n\treturn headers;\n};\n\n// returns a Middleware that checks if the user is authenticated\n// if the user is not authenticated, it redirects to the redirectUrl\n// if the user is authenticated, it adds the session to the headers\nconst createAuthMiddleware =\n\t(options: MiddlewareOptions = {}) =>\n\tasync (req: NextRequest) => {\n\t\tsetLogger(options.logLevel);\n\t\tlogger.debug('[Auth middleware] Starts');\n\n\t\tconst sessionJwt = getSessionJwt(req, options);\n\n\t\t// check if the user is authenticated\n\t\tlet session: AuthenticationInfo | undefined;\n\t\tlet validToken = false;\n\t\ttry {\n\t\t\tsession = await getGlobalSdk({\n\t\t\t\tprojectId: options.projectId,\n\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t}).validateJwt(sessionJwt);\n\t\t\tvalidToken = true;\n\t\t\tlogger.debug('[Auth middleware] Session JWT is valid');\n\t\t} catch (err) {\n\t\t\tlogger.debug('[Auth middleware] Failed to validate session JWT', err);\n\n\t\t\t// Try to validate the refresh token instead\n\t\t\tconst refreshJwt = getRefreshJwt(req, options);\n\t\t\tif (refreshJwt) {\n\t\t\t\tlogger.debug('[Auth middleware] Attempting to validate refresh token');\n\t\t\t\ttry {\n\t\t\t\t\tawait getGlobalSdk({\n\t\t\t\t\t\tprojectId: options.projectId,\n\t\t\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t\t\t}).validateJwt(refreshJwt);\n\n\t\t\t\t\tlogger.debug('[Auth middleware] Refresh token is valid');\n\t\t\t\t\tvalidToken = true;\n\t\t\t\t} catch (refreshErr) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t'[Auth middleware] Refresh token validation failed',\n\t\t\t\t\t\trefreshErr\n\t\t\t\t\t);\n\t\t\t\t\t// Refresh token validation failed, continue to redirect logic below\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we don't have a valid session or refresh token and this is a private route, redirect\n\t\t\tif (!validToken && !isPublicRoute(req, options)) {\n\t\t\t\tconst redirectUrl = options.redirectUrl || DEFAULT_PUBLIC_ROUTES.signIn;\n\t\t\t\tconst url = req.nextUrl.clone();\n\t\t\t\t// Create a URL object for redirectUrl. 'http://example.com' is just a placeholder.\n\t\t\t\tconst parsedRedirectUrl = new URL(redirectUrl, 'http://example.com');\n\t\t\t\turl.pathname = parsedRedirectUrl.pathname;\n\n\t\t\t\tconst searchParams = mergeSearchParams(\n\t\t\t\t\turl.search,\n\t\t\t\t\tparsedRedirectUrl.search\n\t\t\t\t);\n\t\t\t\tif (searchParams) {\n\t\t\t\t\turl.search = searchParams;\n\t\t\t\t}\n\t\t\t\tlogger.debug(`[Auth middleware] Redirecting to ${redirectUrl}`);\n\t\t\t\treturn NextResponse.redirect(url);\n\t\t\t}\n\t\t}\n\n\t\tlogger.debug('[Auth middleware] finishes');\n\n\t\t// Add the session to the request headers and continue\n\t\tconst headers = addSessionToHeadersIfExists(req.headers, session);\n\t\treturn NextResponse.next({\n\t\t\trequest: {\n\t\t\t\theaders\n\t\t\t}\n\t\t});\n\t};\n\nexport default createAuthMiddleware;\n"],"names":[],"mappings":";;;;;;;AAgDA,MAAM,aAAa,GAAG,CACrB,GAAgB,EAChB,OAA0B,KACH;AACvB,IAAA,IAAI,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,GAAG,EAAE;AACR,QAAA,OAAO,GAAG,CAAC;KACX;AAED,IAAA,GAAG,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,CACrB,OAAO,EAAE,iBAAiB,IAAI,UAAU,CAAC,sBAAsB,CAC/D,EAAE,KAAK,CAAC;IACT,IAAI,GAAG,EAAE;AACR,QAAA,OAAO,GAAG,CAAC;KACX;AACD,IAAA,OAAO,SAAS,CAAC;AAClB,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CACrB,GAAgB,EAChB,OAA0B,KACH;AACvB,IAAA,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,CAClC,OAAO,EAAE,sBAAsB,IAAI,KAAK,CACxC,EAAE,KAAK,CAAC;AACT,IAAA,OAAO,UAAU,CAAC;AACnB,CAAC,CAAC;AAEF,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAE,IAAY,KAAI;IAC1D,IAAI,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;;IAG/D,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpD,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,CAAI,CAAA,EAAA,YAAY,CAAG,CAAA,CAAA,CAAC,CAAC;AAE9C,IAAA,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzB,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,GAAgB,EAAE,OAA0B,KAAI;;IAEtE,MAAM,EAAE,YAAY,GAAG,EAAE,EAAE,aAAa,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC;AAC1D,IAAA,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;AAEjC,IAAA,MAAM,oBAAoB,GAAG,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,QAAQ,CACzE,QAAQ,CACR,CAAC;AAEF,IAAA,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE;AAC5B,QAAA,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7B,YAAA,MAAM,CAAC,IAAI,CACV,0EAA0E,CAC1E,CAAC;SACF;AACD,QAAA,QACC,oBAAoB;AACpB,YAAA,YAAY,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,EAChE;KACF;AAED,IAAA,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE;AAC7B,QAAA,QACC,oBAAoB;AACpB,YAAA,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,kBAAkB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,EAClE;KACF;;AAGD,IAAA,OAAO,oBAAoB,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,2BAA2B,GAAG,CACnC,OAAgB,EAChB,OAAuC,KAC3B;IACZ,IAAI,OAAO,EAAE;AACZ,QAAA,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;QAC5C,cAAc,CAAC,GAAG,CACjB,sBAAsB,EACtB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CACvD,CAAC;AACF,QAAA,OAAO,cAAc,CAAC;KACtB;AACD,IAAA,OAAO,OAAO,CAAC;AAChB,CAAC,CAAC;AAEF;AACA;AACA;AACA,MAAM,oBAAoB,GACzB,CAAC,OAAA,GAA6B,EAAE,KAChC,OAAO,GAAgB,KAAI;AAC1B,IAAA,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAC5B,IAAA,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IAEzC,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;;AAG/C,IAAA,IAAI,OAAuC,CAAC;IAC5C,IAAI,UAAU,GAAG,KAAK,CAAC;AACvB,IAAA,IAAI;QACH,OAAO,GAAG,MAAM,YAAY,CAAC;YAC5B,SAAS,EAAE,OAAO,CAAC,SAAS;YAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;AACxB,SAAA,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;QAC3B,UAAU,GAAG,IAAI,CAAC;AAClB,QAAA,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;KACvD;IAAC,OAAO,GAAG,EAAE;AACb,QAAA,MAAM,CAAC,KAAK,CAAC,kDAAkD,EAAE,GAAG,CAAC,CAAC;;QAGtE,MAAM,UAAU,GAAG,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC/C,IAAI,UAAU,EAAE;AACf,YAAA,MAAM,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;AACvE,YAAA,IAAI;AACH,gBAAA,MAAM,YAAY,CAAC;oBAClB,SAAS,EAAE,OAAO,CAAC,SAAS;oBAC5B,OAAO,EAAE,OAAO,CAAC,OAAO;AACxB,iBAAA,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;AAE3B,gBAAA,MAAM,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;gBACzD,UAAU,GAAG,IAAI,CAAC;aAClB;YAAC,OAAO,UAAU,EAAE;AACpB,gBAAA,MAAM,CAAC,KAAK,CACX,mDAAmD,EACnD,UAAU,CACV,CAAC;;aAEF;SACD;;QAGD,IAAI,CAAC,UAAU,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,EAAE;YAChD,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,qBAAqB,CAAC,MAAM,CAAC;YACxE,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;;YAEhC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;AACrE,YAAA,GAAG,CAAC,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC;AAE1C,YAAA,MAAM,YAAY,GAAG,iBAAiB,CACrC,GAAG,CAAC,MAAM,EACV,iBAAiB,CAAC,MAAM,CACxB,CAAC;YACF,IAAI,YAAY,EAAE;AACjB,gBAAA,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC;aAC1B;AACD,YAAA,MAAM,CAAC,KAAK,CAAC,oCAAoC,WAAW,CAAA,CAAE,CAAC,CAAC;AAChE,YAAA,OAAO,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;SAClC;KACD;AAED,IAAA,MAAM,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;;IAG3C,MAAM,OAAO,GAAG,2BAA2B,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAClE,OAAO,YAAY,CAAC,IAAI,CAAC;AACxB,QAAA,OAAO,EAAE;YACR,OAAO;AACP,SAAA;AACD,KAAA,CAAC,CAAC;AACJ;;;;"}
1
+ {"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport descopeSdk from '@descope/node-sdk';\nimport { DEFAULT_PUBLIC_ROUTES, DESCOPE_SESSION_HEADER } from './constants';\nimport { getGlobalSdk } from './sdk';\nimport { mergeSearchParams } from './utils';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.NEXT_PUBLIC_DESCOPE_BASE_URL\n\tbaseUrl?: string;\n\n\t// The URL to redirect to if the user is not authenticated\n\t// Defaults to process.env.SIGN_IN_ROUTE or '/sign-in' if not provided\n\t// NOTE: In case it contains query parameters that exist in the original URL, they will override the original query parameters. e.g. if the original URL is /page?param1=1&param2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3&param2=2\n\tredirectUrl?: string;\n\n\t// An array of public routes that do not require authentication\n\t// In addition to the default public routes:\n\t// - process.env.SIGN_IN_ROUTE or /sign-in if not provided\n\t// - process.env.SIGN_UP_ROUTE or /sign-up if not provided\n\tpublicRoutes?: string[];\n\n\t// An array of private routes that require authentication\n\t// If privateRoutes is defined, routes not listed in this array will default to public routes\n\tprivateRoutes?: string[];\n\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\t// Used to refresh the session when the JWT expires\n\trefreshTokenCookieName?: string;\n};\n\nconst getSessionJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tlet jwt = req.headers?.get('Authorization')?.split(' ')[1];\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\n\tjwt = req.cookies?.get(\n\t\toptions?.sessionCookieName || descopeSdk.SessionTokenCookieName\n\t)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\n};\n\nconst getRefreshJwt = (\n\treq: NextRequest,\n\toptions: MiddlewareOptions\n): string | undefined => {\n\tconst refreshJwt = req.cookies?.get(\n\t\toptions?.refreshTokenCookieName || 'DSR'\n\t)?.value;\n\treturn refreshJwt;\n};\n\nconst matchWildcardRoute = (route: string, path: string) => {\n\tlet regexPattern = route.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\n\t// Convert wildcard (*) to match path segments only\n\tregexPattern = regexPattern.replace(/\\*/g, '[^/]*');\n\tconst regex = new RegExp(`^${regexPattern}$`);\n\n\treturn regex.test(path);\n};\n\nconst isPublicRoute = (req: NextRequest, options: MiddlewareOptions) => {\n\t// Ensure publicRoutes and privateRoutes are arrays, defaulting to empty arrays if not defined\n\tconst { publicRoutes = [], privateRoutes = [] } = options;\n\tconst { pathname } = req.nextUrl;\n\n\tconst isDefaultPublicRoute = Object.values(DEFAULT_PUBLIC_ROUTES).includes(\n\t\tpathname\n\t);\n\n\tif (publicRoutes.length > 0) {\n\t\tif (privateRoutes.length > 0) {\n\t\t\tlogger.warn(\n\t\t\t\t'Both publicRoutes and privateRoutes are defined. Ignoring privateRoutes.'\n\t\t\t);\n\t\t}\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\tpublicRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\tif (privateRoutes.length > 0) {\n\t\treturn (\n\t\t\tisDefaultPublicRoute ||\n\t\t\t!privateRoutes.some((route) => matchWildcardRoute(route, pathname))\n\t\t);\n\t}\n\n\t// If no routes are provided, all routes are private\n\treturn isDefaultPublicRoute;\n};\n\nconst removeSessionHeader = (headers: Headers): Headers => {\n\tconst requestHeaders = new Headers(headers);\n\trequestHeaders.delete(DESCOPE_SESSION_HEADER);\n\treturn requestHeaders;\n};\n\n// returns a Middleware that checks if the user is authenticated\n// if the user is not authenticated, it redirects to the redirectUrl\nconst createAuthMiddleware =\n\t(options: MiddlewareOptions = {}) =>\n\tasync (req: NextRequest) => {\n\t\tsetLogger(options.logLevel);\n\t\tlogger.debug('[Auth middleware] Starts');\n\n\t\tconst sessionJwt = getSessionJwt(req, options);\n\n\t\t// check if the user is authenticated\n\t\tlet validToken = false;\n\t\ttry {\n\t\t\tawait getGlobalSdk({\n\t\t\t\tprojectId: options.projectId,\n\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t}).validateJwt(sessionJwt);\n\t\t\tvalidToken = true;\n\t\t\tlogger.debug('[Auth middleware] Session JWT is valid');\n\t\t} catch (err) {\n\t\t\tlogger.debug('[Auth middleware] Failed to validate session JWT', err);\n\n\t\t\t// Try to validate the refresh token instead\n\t\t\tconst refreshJwt = getRefreshJwt(req, options);\n\t\t\tif (refreshJwt) {\n\t\t\t\tlogger.debug('[Auth middleware] Attempting to validate refresh token');\n\t\t\t\ttry {\n\t\t\t\t\tawait getGlobalSdk({\n\t\t\t\t\t\tprojectId: options.projectId,\n\t\t\t\t\t\tbaseUrl: options.baseUrl\n\t\t\t\t\t}).validateJwt(refreshJwt);\n\n\t\t\t\t\tlogger.debug('[Auth middleware] Refresh token is valid');\n\t\t\t\t\tvalidToken = true;\n\t\t\t\t} catch (refreshErr) {\n\t\t\t\t\tlogger.debug(\n\t\t\t\t\t\t'[Auth middleware] Refresh token validation failed',\n\t\t\t\t\t\trefreshErr\n\t\t\t\t\t);\n\t\t\t\t\t// Refresh token validation failed, continue to redirect logic below\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If we don't have a valid session or refresh token and this is a private route, redirect\n\t\t\tif (!validToken && !isPublicRoute(req, options)) {\n\t\t\t\tconst redirectUrl = options.redirectUrl || DEFAULT_PUBLIC_ROUTES.signIn;\n\t\t\t\tconst url = req.nextUrl.clone();\n\t\t\t\t// Create a URL object for redirectUrl. 'http://example.com' is just a placeholder.\n\t\t\t\tconst parsedRedirectUrl = new URL(redirectUrl, 'http://example.com');\n\t\t\t\turl.pathname = parsedRedirectUrl.pathname;\n\n\t\t\t\tconst searchParams = mergeSearchParams(\n\t\t\t\t\turl.search,\n\t\t\t\t\tparsedRedirectUrl.search\n\t\t\t\t);\n\t\t\t\tif (searchParams) {\n\t\t\t\t\turl.search = searchParams;\n\t\t\t\t}\n\t\t\t\tlogger.debug(`[Auth middleware] Redirecting to ${redirectUrl}`);\n\t\t\t\treturn NextResponse.redirect(url);\n\t\t\t}\n\t\t}\n\n\t\tlogger.debug('[Auth middleware] finishes');\n\n\t\tconst headers = removeSessionHeader(req.headers);\n\t\treturn NextResponse.next({\n\t\t\trequest: {\n\t\t\t\theaders\n\t\t\t}\n\t\t});\n\t};\n\nexport default createAuthMiddleware;\n"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  const DESCOPE_SESSION_HEADER = 'x-descope-session';
2
2
  const baseHeaders = {
3
3
  'x-descope-sdk-name': 'nextjs',
4
- 'x-descope-sdk-version': "0.15.55"
4
+ 'x-descope-sdk-version': "0.15.57"
5
5
  };
6
6
  const DEFAULT_PUBLIC_ROUTES = {
7
7
  signIn: process.env.SIGN_IN_ROUTE || '/sign-in',
@@ -1,58 +1,51 @@
1
1
  import descopeSdk from '@descope/node-sdk';
2
2
  import { headers, cookies } from 'next/headers.js';
3
- import { DESCOPE_SESSION_HEADER } from './constants.js';
4
3
  import { getGlobalSdk } from './sdk.js';
5
4
  import { setLogger, logger } from './logger.js';
6
5
 
7
- const extractSession = (descopeSession) => {
8
- if (!descopeSession) {
9
- return undefined;
10
- }
11
- try {
12
- const authInfo = JSON.parse(Buffer.from(descopeSession, 'base64').toString());
13
- return authInfo;
6
+ const getSessionCookieName = (config) => config?.sessionCookieName || descopeSdk.SessionTokenCookieName;
7
+ // tries to validate the Authorization header,
8
+ // if it doesn't exist or is invalid, it will attempt to validate the session cookie
9
+ const getSessionFromAuthorizationOrCookie = async (authorization, cookieJwt, config) => {
10
+ const sessionJwt = authorization?.split(' ')[1];
11
+ if (sessionJwt) {
12
+ try {
13
+ const sdk = getGlobalSdk(config);
14
+ return await sdk.validateJwt(sessionJwt);
15
+ }
16
+ catch (err) {
17
+ logger.debug('Error validating session from Authorization header', err);
18
+ }
14
19
  }
15
- catch (err) {
20
+ logger.debug('attempting to get session from cookie');
21
+ if (!cookieJwt) {
22
+ logger.debug('Session cookie not found');
16
23
  return undefined;
17
24
  }
18
- };
19
- const getSessionFromCookie = async (config) => {
20
- logger.debug('attempting to get session from cookie');
21
25
  try {
22
- const sessionCookie = (await cookies()).get(config?.sessionCookieName || descopeSdk.SessionTokenCookieName);
23
- if (!sessionCookie?.value) {
24
- logger.debug('Session cookie not found');
25
- return undefined;
26
- }
27
26
  const sdk = getGlobalSdk(config);
28
- return await sdk.validateJwt(sessionCookie.value);
27
+ return await sdk.validateJwt(cookieJwt);
29
28
  }
30
29
  catch (err) {
31
30
  logger.debug('Error getting session from cookie', err);
32
31
  return undefined;
33
32
  }
34
33
  };
35
- // tries to extract the session header,
36
- // if it doesn't exist, it will attempt to get the session from the cookie
37
- const extractOrGetSession = async (sessionHeader, config) => {
38
- const session = extractSession(sessionHeader);
39
- if (session) {
40
- return session;
41
- }
42
- return getSessionFromCookie(config);
43
- };
44
- // returns the session token if it exists in the headers
34
+ // returns the session token if it exists in the Authorization header or cookie
45
35
  const session = async (config) => {
46
36
  setLogger(config?.logLevel);
47
- // first attempt to get the session from the headers
48
37
  const reqHeaders = await headers();
49
- const sessionHeader = reqHeaders.get(DESCOPE_SESSION_HEADER);
50
- return extractOrGetSession(sessionHeader, config);
38
+ const cookieJwt = (await cookies()).get(getSessionCookieName(config))?.value;
39
+ return getSessionFromAuthorizationOrCookie(reqHeaders.get('Authorization'), cookieJwt, config);
51
40
  };
52
- // returns the session token if it exists in the request headers
41
+ // returns the session token if it exists in the request Authorization header or cookie
53
42
  const getSession = async (req, config) => {
54
43
  setLogger(config?.logLevel);
55
- return extractOrGetSession(req.headers[DESCOPE_SESSION_HEADER.toLowerCase()], config);
44
+ const { authorization } = req.headers;
45
+ return getSessionFromAuthorizationOrCookie(typeof authorization === 'string' ? authorization : undefined,
46
+ // Pages Router request - next/headers cookies() is not available here,
47
+ // so the session cookie must be read directly from the request
48
+ req.cookies?.[getSessionCookieName(config)], config);
56
49
  };
57
50
 
58
51
  export { getSession, session };
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["import descopeSdk, { AuthenticationInfo } from '@descope/node-sdk';\nimport { NextApiRequest } from 'next';\nimport { cookies, headers } from 'next/headers';\nimport { DESCOPE_SESSION_HEADER } from './constants';\nimport { getGlobalSdk, CreateSdkParams } from './sdk';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype SessionConfig = CreateSdkParams & {\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\trefreshTokenCookieName?: string;\n};\n\nconst extractSession = (\n\tdescopeSession?: string\n): AuthenticationInfo | undefined => {\n\tif (!descopeSession) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst authInfo = JSON.parse(\n\t\t\tBuffer.from(descopeSession, 'base64').toString()\n\t\t) as AuthenticationInfo;\n\t\treturn authInfo;\n\t} catch (err) {\n\t\treturn undefined;\n\t}\n};\n\nconst getSessionFromCookie = async (\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tlogger.debug('attempting to get session from cookie');\n\ttry {\n\t\tconst sessionCookie = (await cookies()).get(\n\t\t\tconfig?.sessionCookieName || descopeSdk.SessionTokenCookieName\n\t\t);\n\t\tif (!sessionCookie?.value) {\n\t\t\tlogger.debug('Session cookie not found');\n\t\t\treturn undefined;\n\t\t}\n\t\tconst sdk = getGlobalSdk(config);\n\t\treturn await sdk.validateJwt(sessionCookie.value);\n\t} catch (err) {\n\t\tlogger.debug('Error getting session from cookie', err);\n\t\treturn undefined;\n\t}\n};\n\n// tries to extract the session header,\n// if it doesn't exist, it will attempt to get the session from the cookie\nconst extractOrGetSession = async (\n\tsessionHeader?: string,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tconst session = extractSession(sessionHeader);\n\tif (session) {\n\t\treturn session;\n\t}\n\n\treturn getSessionFromCookie(config);\n};\n\n// returns the session token if it exists in the headers\nexport const session = async (\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\t// first attempt to get the session from the headers\n\tconst reqHeaders = await headers();\n\tconst sessionHeader = reqHeaders.get(DESCOPE_SESSION_HEADER);\n\treturn extractOrGetSession(sessionHeader, config);\n};\n\n// returns the session token if it exists in the request headers\nexport const getSession = async (\n\treq: NextApiRequest,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\treturn extractOrGetSession(\n\t\treq.headers[DESCOPE_SESSION_HEADER.toLowerCase()] as string,\n\t\tconfig\n\t);\n};\n"],"names":[],"mappings":";;;;;;AAuBA,MAAM,cAAc,GAAG,CACtB,cAAuB,KACY;IACnC,IAAI,CAAC,cAAc,EAAE;AACpB,QAAA,OAAO,SAAS,CAAC;KACjB;AACD,IAAA,IAAI;AACH,QAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAC1B,MAAM,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAC1B,CAAC;AACxB,QAAA,OAAO,QAAQ,CAAC;KAChB;IAAC,OAAO,GAAG,EAAE;AACb,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,OAC5B,MAAsB,KACsB;AAC5C,IAAA,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;AACtD,IAAA,IAAI;AACH,QAAA,MAAM,aAAa,GAAG,CAAC,MAAM,OAAO,EAAE,EAAE,GAAG,CAC1C,MAAM,EAAE,iBAAiB,IAAI,UAAU,CAAC,sBAAsB,CAC9D,CAAC;AACF,QAAA,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE;AAC1B,YAAA,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AACzC,YAAA,OAAO,SAAS,CAAC;SACjB;AACD,QAAA,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACjC,OAAO,MAAM,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;KAClD;IAAC,OAAO,GAAG,EAAE;AACb,QAAA,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;AACvD,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF;AACA;AACA,MAAM,mBAAmB,GAAG,OAC3B,aAAsB,EACtB,MAAsB,KACsB;AAC5C,IAAA,MAAM,OAAO,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IAC9C,IAAI,OAAO,EAAE;AACZ,QAAA,OAAO,OAAO,CAAC;KACf;AAED,IAAA,OAAO,oBAAoB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF;MACa,OAAO,GAAG,OACtB,MAAsB,KACsB;AAC5C,IAAA,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;;AAE5B,IAAA,MAAM,UAAU,GAAG,MAAM,OAAO,EAAE,CAAC;IACnC,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;AAC7D,IAAA,OAAO,mBAAmB,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;AACnD,EAAE;AAEF;AACa,MAAA,UAAU,GAAG,OACzB,GAAmB,EACnB,MAAsB,KACsB;AAC5C,IAAA,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC5B,IAAA,OAAO,mBAAmB,CACzB,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,WAAW,EAAE,CAAW,EAC3D,MAAM,CACN,CAAC;AACH;;;;"}
1
+ {"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["import descopeSdk, { AuthenticationInfo } from '@descope/node-sdk';\nimport { NextApiRequest } from 'next';\nimport { cookies, headers } from 'next/headers';\nimport { getGlobalSdk, CreateSdkParams } from './sdk';\nimport { LogLevel } from '../types';\nimport { logger, setLogger } from './logger';\n\ntype SessionConfig = CreateSdkParams & {\n\t// The log level to use for the middleware\n\t// Defaults to 'info'\n\tlogLevel?: LogLevel;\n\n\t// The name of the session cookie to look for the JWT\n\t// Defaults to 'DS'\n\t// Note: The middleware will also look for the JWT in the Authorization header\n\tsessionCookieName?: string;\n\n\t// The name of the refresh token cookie\n\t// Defaults to 'DSR'\n\trefreshTokenCookieName?: string;\n};\n\nconst getSessionCookieName = (config?: SessionConfig) =>\n\tconfig?.sessionCookieName || descopeSdk.SessionTokenCookieName;\n\n// tries to validate the Authorization header,\n// if it doesn't exist or is invalid, it will attempt to validate the session cookie\nconst getSessionFromAuthorizationOrCookie = async (\n\tauthorization: string | null | undefined,\n\tcookieJwt: string | undefined,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tconst sessionJwt = authorization?.split(' ')[1];\n\tif (sessionJwt) {\n\t\ttry {\n\t\t\tconst sdk = getGlobalSdk(config);\n\t\t\treturn await sdk.validateJwt(sessionJwt);\n\t\t} catch (err) {\n\t\t\tlogger.debug('Error validating session from Authorization header', err);\n\t\t}\n\t}\n\n\tlogger.debug('attempting to get session from cookie');\n\tif (!cookieJwt) {\n\t\tlogger.debug('Session cookie not found');\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst sdk = getGlobalSdk(config);\n\t\treturn await sdk.validateJwt(cookieJwt);\n\t} catch (err) {\n\t\tlogger.debug('Error getting session from cookie', err);\n\t\treturn undefined;\n\t}\n};\n\n// returns the session token if it exists in the Authorization header or cookie\nexport const session = async (\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\tconst reqHeaders = await headers();\n\tconst cookieJwt = (await cookies()).get(getSessionCookieName(config))?.value;\n\treturn getSessionFromAuthorizationOrCookie(\n\t\treqHeaders.get('Authorization'),\n\t\tcookieJwt,\n\t\tconfig\n\t);\n};\n\n// returns the session token if it exists in the request Authorization header or cookie\nexport const getSession = async (\n\treq: NextApiRequest,\n\tconfig?: SessionConfig\n): Promise<AuthenticationInfo | undefined> => {\n\tsetLogger(config?.logLevel);\n\tconst { authorization } = req.headers;\n\treturn getSessionFromAuthorizationOrCookie(\n\t\ttypeof authorization === 'string' ? authorization : undefined,\n\t\t// Pages Router request - next/headers cookies() is not available here,\n\t\t// so the session cookie must be read directly from the request\n\t\treq.cookies?.[getSessionCookieName(config)],\n\t\tconfig\n\t);\n};\n"],"names":[],"mappings":";;;;;AAsBA,MAAM,oBAAoB,GAAG,CAAC,MAAsB,KACnD,MAAM,EAAE,iBAAiB,IAAI,UAAU,CAAC,sBAAsB,CAAC;AAEhE;AACA;AACA,MAAM,mCAAmC,GAAG,OAC3C,aAAwC,EACxC,SAA6B,EAC7B,MAAsB,KACsB;IAC5C,MAAM,UAAU,GAAG,aAAa,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,UAAU,EAAE;AACf,QAAA,IAAI;AACH,YAAA,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AACjC,YAAA,OAAO,MAAM,GAAG,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;SACzC;QAAC,OAAO,GAAG,EAAE;AACb,YAAA,MAAM,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,CAAC,CAAC;SACxE;KACD;AAED,IAAA,MAAM,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACtD,IAAI,CAAC,SAAS,EAAE;AACf,QAAA,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AACzC,QAAA,OAAO,SAAS,CAAC;KACjB;AACD,IAAA,IAAI;AACH,QAAA,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AACjC,QAAA,OAAO,MAAM,GAAG,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;KACxC;IAAC,OAAO,GAAG,EAAE;AACb,QAAA,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;AACvD,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF;MACa,OAAO,GAAG,OACtB,MAAsB,KACsB;AAC5C,IAAA,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC5B,IAAA,MAAM,UAAU,GAAG,MAAM,OAAO,EAAE,CAAC;AACnC,IAAA,MAAM,SAAS,GAAG,CAAC,MAAM,OAAO,EAAE,EAAE,GAAG,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC;AAC7E,IAAA,OAAO,mCAAmC,CACzC,UAAU,CAAC,GAAG,CAAC,eAAe,CAAC,EAC/B,SAAS,EACT,MAAM,CACN,CAAC;AACH,EAAE;AAEF;AACa,MAAA,UAAU,GAAG,OACzB,GAAmB,EACnB,MAAsB,KACsB;AAC5C,IAAA,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;AAC5B,IAAA,MAAM,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;AACtC,IAAA,OAAO,mCAAmC,CACzC,OAAO,aAAa,KAAK,QAAQ,GAAG,aAAa,GAAG,SAAS;;;AAG7D,IAAA,GAAG,CAAC,OAAO,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC,EAC3C,MAAM,CACN,CAAC;AACH;;;;"}
@@ -1,7 +1,7 @@
1
1
  // eslint-disable-next-line import/prefer-default-export
2
2
  const baseHeaders = {
3
3
  'x-descope-sdk-name': 'nextjs',
4
- 'x-descope-sdk-version': "0.15.55"
4
+ 'x-descope-sdk-version': "0.15.57"
5
5
  };
6
6
 
7
7
  export { baseHeaders };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@descope/nextjs-sdk",
3
- "version": "0.15.55",
3
+ "version": "0.15.57",
4
4
  "description": "Descope NextJS SDK",
5
5
  "author": "Descope Team <info@descope.com>",
6
6
  "homepage": "https://github.com/descope/descope-js",
@@ -64,8 +64,8 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@descope/node-sdk": "2.8.0",
67
- "@descope/core-js-sdk": "2.67.0",
68
67
  "@descope/react-sdk": "2.30.6",
68
+ "@descope/core-js-sdk": "2.67.0",
69
69
  "@descope/web-component": "3.70.3"
70
70
  },
71
71
  "devDependencies": {