@descope/nextjs-sdk 0.7.1 → 0.8.0
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.
- package/README.md +14 -1
- package/dist/cjs/server/authMiddleware.js +4 -2
- package/dist/cjs/server/authMiddleware.js.map +1 -1
- package/dist/cjs/server/constants.js +1 -1
- package/dist/cjs/server/sdk.js.map +1 -1
- package/dist/cjs/server/session.js +32 -5
- package/dist/cjs/server/session.js.map +1 -1
- package/dist/cjs/shared/constants.js +1 -1
- package/dist/esm/server/authMiddleware.js +4 -2
- package/dist/esm/server/authMiddleware.js.map +1 -1
- package/dist/esm/server/constants.js +1 -1
- package/dist/esm/server/sdk.js.map +1 -1
- package/dist/esm/server/session.js +33 -6
- package/dist/esm/server/session.js.map +1 -1
- package/dist/esm/shared/constants.js +1 -1
- package/dist/types/server/sdk.d.ts +5 -4
- package/dist/types/server/session.d.ts +3 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -200,7 +200,7 @@ This setup ensures that you can clearly define which routes in your application
|
|
|
200
200
|
|
|
201
201
|
use the `session()` helper to read session information in Server Components and Route handlers.
|
|
202
202
|
|
|
203
|
-
Note: `session()`
|
|
203
|
+
Note: While using `authMiddleware` is still recommended for session management (because it validates the session only once), `session()` can function without it. If `authMiddleware` does not set a session, `session()` will attempt to retrieve the session token from cookies, then parse and validate it.
|
|
204
204
|
|
|
205
205
|
Server Component:
|
|
206
206
|
|
|
@@ -234,6 +234,19 @@ export async function GET() {
|
|
|
234
234
|
}
|
|
235
235
|
```
|
|
236
236
|
|
|
237
|
+
##### Optional Parameters
|
|
238
|
+
|
|
239
|
+
If the middleware did not set a session, The `session()` function will attempt to retrieve the session token from cookies and validates it, this requires the project ID to be either set in the environment variables or passed as a parameter to the function.
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
session({ projectId?: string, baseUrl?: string })
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
- **projectId:** The Descope Project ID. If not provided, the function will fall back to `DESCOPE_PROJECT_ID` from the environment variables.
|
|
246
|
+
- **baseUrl:** The Descope API base URL.
|
|
247
|
+
|
|
248
|
+
This allows developers to use `session()` even if the project ID is not set in the environment.
|
|
249
|
+
|
|
237
250
|
#### Access Descope SDK in server side
|
|
238
251
|
|
|
239
252
|
Use `createSdk` function to create Descope SDK in server side.
|
|
@@ -34,10 +34,12 @@ const isPublicRoute = (req, options) => {
|
|
|
34
34
|
if (privateRoutes.length > 0) {
|
|
35
35
|
console.warn('Both publicRoutes and privateRoutes are defined. Ignoring privateRoutes.');
|
|
36
36
|
}
|
|
37
|
-
return isDefaultPublicRoute ||
|
|
37
|
+
return (isDefaultPublicRoute ||
|
|
38
|
+
publicRoutes.some((route) => matchWildcardRoute(route, pathname)));
|
|
38
39
|
}
|
|
39
40
|
if (privateRoutes.length > 0) {
|
|
40
|
-
return (isDefaultPublicRoute ||
|
|
41
|
+
return (isDefaultPublicRoute ||
|
|
42
|
+
!privateRoutes.some((route) => matchWildcardRoute(route, pathname)));
|
|
41
43
|
}
|
|
42
44
|
// If no routes are provided, all routes are private
|
|
43
45
|
return isDefaultPublicRoute;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { 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';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.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¶m2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3¶m2=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\nconst getSessionJwt = (req: NextRequest): 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(descopeSdk.SessionTokenCookieName)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\n};\n\nconst matchWildcardRoute = (route: string, path: string) => {\n\tlet regexPattern = route.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n
|
|
1
|
+
{"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { 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';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.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¶m2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3¶m2=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\nconst getSessionJwt = (req: NextRequest): 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(descopeSdk.SessionTokenCookieName)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\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\tconsole.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\tconsole.debug('Auth middleware starts');\n\n\t\tconst jwt = getSessionJwt(req);\n\n\t\t// check if the user is authenticated\n\t\tlet session: AuthenticationInfo | undefined;\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(jwt);\n\t\t} catch (err) {\n\t\t\tconsole.debug('Auth middleware, Failed to validate JWT', err);\n\t\t\tif (!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\tconsole.debug(`Auth middleware, Redirecting to ${redirectUrl}`);\n\t\t\t\treturn NextResponse.redirect(url);\n\t\t\t}\n\t\t}\n\n\t\tconsole.debug('Auth middleware finishes');\n\t\t// add the session to the request, if it exists\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","DESCOPE_SESSION_HEADER","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.
|
|
6
|
+
'x-descope-sdk-version': "0.8.0"
|
|
7
7
|
};
|
|
8
8
|
const DEFAULT_PUBLIC_ROUTES = {
|
|
9
9
|
signIn: process.env.SIGN_IN_ROUTE || '/sign-in',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import descopeSdk from '@descope/node-sdk';\nimport { baseHeaders } from './constants';\n\ntype Sdk = ReturnType<typeof descopeSdk>;\ntype
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import descopeSdk from '@descope/node-sdk';\nimport { baseHeaders } from './constants';\n\ntype Sdk = ReturnType<typeof descopeSdk>;\ntype CreateServerSdkParams = Omit<\n\tParameters<typeof descopeSdk>[0],\n\t'projectId'\n> & {\n\tprojectId?: string | undefined;\n};\n\ntype CreateSdkParams = Pick<CreateServerSdkParams, 'projectId' | 'baseUrl'>;\n\nlet globalSdk: Sdk;\n\nexport const createSdk = (config?: CreateServerSdkParams): Sdk =>\n\tdescopeSdk({\n\t\t...config,\n\t\tprojectId: config?.projectId || process.env.DESCOPE_PROJECT_ID,\n\t\tmanagementKey: config?.managementKey || process.env.DESCOPE_MANAGEMENT_KEY,\n\t\tbaseUrl: config?.baseUrl || process.env.DESCOPE_BASE_URL,\n\t\tbaseHeaders: {\n\t\t\t...config?.baseHeaders,\n\t\t\t...baseHeaders\n\t\t}\n\t});\n\nexport const getGlobalSdk = (config?: CreateSdkParams): Sdk => {\n\tif (!globalSdk) {\n\t\tif (!config?.projectId && !process.env.DESCOPE_PROJECT_ID) {\n\t\t\tthrow new Error('Descope project ID is required to create the SDK');\n\t\t}\n\t\tglobalSdk = createSdk(config);\n\t}\n\n\treturn globalSdk;\n};\n\nexport type { CreateSdkParams };\n"],"names":["baseHeaders"],"mappings":";;;;;AAaA,IAAI,SAAc,CAAC;AAEN,MAAA,SAAS,GAAG,CAAC,MAA8B,KACvD,UAAU,CAAC;AACV,IAAA,GAAG,MAAM;IACT,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;IAC9D,aAAa,EAAE,MAAM,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB;IAC1E,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;AACxD,IAAA,WAAW,EAAE;QACZ,GAAG,MAAM,EAAE,WAAW;AACtB,QAAA,GAAGA,qBAAW;AACd,KAAA;AACD,CAAA,EAAE;AAES,MAAA,YAAY,GAAG,CAAC,MAAwB,KAAS;IAC7D,IAAI,CAAC,SAAS,EAAE;AACf,QAAA,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE;AAC1D,YAAA,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;SACpE;AACD,QAAA,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;KAC9B;AAED,IAAA,OAAO,SAAS,CAAC;AAClB;;;;;"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var descopeSdk = require('@descope/node-sdk');
|
|
3
4
|
var headers_js = require('next/headers.js');
|
|
4
5
|
var constants = require('./constants.js');
|
|
6
|
+
var sdk = require('./sdk.js');
|
|
5
7
|
|
|
8
|
+
/* eslint-disable no-console */
|
|
6
9
|
const extractSession = (descopeSession) => {
|
|
7
10
|
if (!descopeSession) {
|
|
8
11
|
return undefined;
|
|
@@ -15,16 +18,40 @@ const extractSession = (descopeSession) => {
|
|
|
15
18
|
return undefined;
|
|
16
19
|
}
|
|
17
20
|
};
|
|
21
|
+
const getSessionFromCookie = async (config) => {
|
|
22
|
+
try {
|
|
23
|
+
const sessionCookie = (await headers_js.cookies()).get(descopeSdk.SessionTokenCookieName);
|
|
24
|
+
if (!sessionCookie?.value) {
|
|
25
|
+
console.debug('Session cookie not found');
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const sdk$1 = sdk.getGlobalSdk(config);
|
|
29
|
+
const res = await sdk$1.validateJwt(sessionCookie.value);
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
console.debug('Error getting session from cookie', err);
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
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
|
+
};
|
|
18
46
|
// returns the session token if it exists in the headers
|
|
19
|
-
|
|
20
|
-
|
|
47
|
+
const session = async (config) => {
|
|
48
|
+
// first attempt to get the session from the headers
|
|
21
49
|
const reqHeaders = await headers_js.headers();
|
|
22
50
|
const sessionHeader = reqHeaders.get(constants.DESCOPE_SESSION_HEADER);
|
|
23
|
-
return
|
|
51
|
+
return extractOrGetSession(sessionHeader, config);
|
|
24
52
|
};
|
|
25
53
|
// returns the session token if it exists in the request headers
|
|
26
|
-
|
|
27
|
-
const getSession = (req) => extractSession(req.headers[constants.DESCOPE_SESSION_HEADER.toLowerCase()]);
|
|
54
|
+
const getSession = async (req, config) => extractOrGetSession(req.headers[constants.DESCOPE_SESSION_HEADER.toLowerCase()], config);
|
|
28
55
|
|
|
29
56
|
exports.getSession = getSession;
|
|
30
57
|
exports.session = session;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport 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';\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?: CreateSdkParams\n): Promise<AuthenticationInfo | undefined> => {\n\ttry {\n\t\tconst sessionCookie = (await cookies()).get(\n\t\t\tdescopeSdk.SessionTokenCookieName\n\t\t);\n\t\tif (!sessionCookie?.value) {\n\t\t\tconsole.debug('Session cookie not found');\n\t\t\treturn undefined;\n\t\t}\n\t\tconst sdk = getGlobalSdk(config);\n\t\tconst res = await sdk.validateJwt(sessionCookie.value);\n\t\treturn res;\n\t} catch (err) {\n\t\tconsole.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?: CreateSdkParams\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?: CreateSdkParams\n): Promise<AuthenticationInfo | undefined> => {\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?: CreateSdkParams\n): Promise<AuthenticationInfo | undefined> =>\n\textractOrGetSession(\n\t\treq.headers[DESCOPE_SESSION_HEADER.toLowerCase()] as string,\n\t\tconfig\n\t);\n"],"names":["cookies","sdk","getGlobalSdk","headers","DESCOPE_SESSION_HEADER"],"mappings":";;;;;;;AAAA;AAOA,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,MAAwB,KACoB;AAC5C,IAAA,IAAI;AACH,QAAA,MAAM,aAAa,GAAG,CAAC,MAAMA,kBAAO,EAAE,EAAE,GAAG,CAC1C,UAAU,CAAC,sBAAsB,CACjC,CAAC;AACF,QAAA,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE;AAC1B,YAAA,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC1C,YAAA,OAAO,SAAS,CAAC;SACjB;AACD,QAAA,MAAMC,KAAG,GAAGC,gBAAY,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,MAAMD,KAAG,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACvD,QAAA,OAAO,GAAG,CAAC;KACX;IAAC,OAAO,GAAG,EAAE;AACb,QAAA,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;AACxD,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF;AACA;AACA,MAAM,mBAAmB,GAAG,OAC3B,aAAsB,EACtB,MAAwB,KACoB;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,MAAwB,KACoB;;AAE5C,IAAA,MAAM,UAAU,GAAG,MAAME,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,MAAwB,KAExB,mBAAmB,CAClB,GAAG,CAAC,OAAO,CAACA,gCAAsB,CAAC,WAAW,EAAE,CAAW,EAC3D,MAAM;;;;;"}
|
|
@@ -32,10 +32,12 @@ const isPublicRoute = (req, options) => {
|
|
|
32
32
|
if (privateRoutes.length > 0) {
|
|
33
33
|
console.warn('Both publicRoutes and privateRoutes are defined. Ignoring privateRoutes.');
|
|
34
34
|
}
|
|
35
|
-
return isDefaultPublicRoute ||
|
|
35
|
+
return (isDefaultPublicRoute ||
|
|
36
|
+
publicRoutes.some((route) => matchWildcardRoute(route, pathname)));
|
|
36
37
|
}
|
|
37
38
|
if (privateRoutes.length > 0) {
|
|
38
|
-
return (isDefaultPublicRoute ||
|
|
39
|
+
return (isDefaultPublicRoute ||
|
|
40
|
+
!privateRoutes.some((route) => matchWildcardRoute(route, pathname)));
|
|
39
41
|
}
|
|
40
42
|
// If no routes are provided, all routes are private
|
|
41
43
|
return isDefaultPublicRoute;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { 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';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.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¶m2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3¶m2=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\nconst getSessionJwt = (req: NextRequest): 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(descopeSdk.SessionTokenCookieName)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\n};\n\nconst matchWildcardRoute = (route: string, path: string) => {\n\tlet regexPattern = route.replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&');\n
|
|
1
|
+
{"version":3,"file":"authMiddleware.js","sources":["../../../src/server/authMiddleware.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport { 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';\n\ntype MiddlewareOptions = {\n\t// The Descope project ID to use for authentication\n\t// Defaults to process.env.DESCOPE_PROJECT_ID\n\tprojectId?: string;\n\n\t// The base URL to use for authentication\n\t// Defaults to process.env.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¶m2=2 and the redirect URL is /sign-in?param1=3, the final redirect URL will be /sign-in?param1=3¶m2=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\nconst getSessionJwt = (req: NextRequest): 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(descopeSdk.SessionTokenCookieName)?.value;\n\tif (jwt) {\n\t\treturn jwt;\n\t}\n\treturn undefined;\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\tconsole.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\tconsole.debug('Auth middleware starts');\n\n\t\tconst jwt = getSessionJwt(req);\n\n\t\t// check if the user is authenticated\n\t\tlet session: AuthenticationInfo | undefined;\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(jwt);\n\t\t} catch (err) {\n\t\t\tconsole.debug('Auth middleware, Failed to validate JWT', err);\n\t\t\tif (!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\tconsole.debug(`Auth middleware, Redirecting to ${redirectUrl}`);\n\t\t\t\treturn NextResponse.redirect(url);\n\t\t\t}\n\t\t}\n\n\t\tconsole.debug('Auth middleware finishes');\n\t\t// add the session to the request, if it exists\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":"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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.
|
|
4
|
+
'x-descope-sdk-version': "0.8.0"
|
|
5
5
|
};
|
|
6
6
|
const DEFAULT_PUBLIC_ROUTES = {
|
|
7
7
|
signIn: process.env.SIGN_IN_ROUTE || '/sign-in',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import descopeSdk from '@descope/node-sdk';\nimport { baseHeaders } from './constants';\n\ntype Sdk = ReturnType<typeof descopeSdk>;\ntype
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import descopeSdk from '@descope/node-sdk';\nimport { baseHeaders } from './constants';\n\ntype Sdk = ReturnType<typeof descopeSdk>;\ntype CreateServerSdkParams = Omit<\n\tParameters<typeof descopeSdk>[0],\n\t'projectId'\n> & {\n\tprojectId?: string | undefined;\n};\n\ntype CreateSdkParams = Pick<CreateServerSdkParams, 'projectId' | 'baseUrl'>;\n\nlet globalSdk: Sdk;\n\nexport const createSdk = (config?: CreateServerSdkParams): Sdk =>\n\tdescopeSdk({\n\t\t...config,\n\t\tprojectId: config?.projectId || process.env.DESCOPE_PROJECT_ID,\n\t\tmanagementKey: config?.managementKey || process.env.DESCOPE_MANAGEMENT_KEY,\n\t\tbaseUrl: config?.baseUrl || process.env.DESCOPE_BASE_URL,\n\t\tbaseHeaders: {\n\t\t\t...config?.baseHeaders,\n\t\t\t...baseHeaders\n\t\t}\n\t});\n\nexport const getGlobalSdk = (config?: CreateSdkParams): Sdk => {\n\tif (!globalSdk) {\n\t\tif (!config?.projectId && !process.env.DESCOPE_PROJECT_ID) {\n\t\t\tthrow new Error('Descope project ID is required to create the SDK');\n\t\t}\n\t\tglobalSdk = createSdk(config);\n\t}\n\n\treturn globalSdk;\n};\n\nexport type { CreateSdkParams };\n"],"names":[],"mappings":";;;AAaA,IAAI,SAAc,CAAC;AAEN,MAAA,SAAS,GAAG,CAAC,MAA8B,KACvD,UAAU,CAAC;AACV,IAAA,GAAG,MAAM;IACT,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB;IAC9D,aAAa,EAAE,MAAM,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,sBAAsB;IAC1E,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;AACxD,IAAA,WAAW,EAAE;QACZ,GAAG,MAAM,EAAE,WAAW;AACtB,QAAA,GAAG,WAAW;AACd,KAAA;AACD,CAAA,EAAE;AAES,MAAA,YAAY,GAAG,CAAC,MAAwB,KAAS;IAC7D,IAAI,CAAC,SAAS,EAAE;AACf,QAAA,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE;AAC1D,YAAA,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;SACpE;AACD,QAAA,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;KAC9B;AAED,IAAA,OAAO,SAAS,CAAC;AAClB;;;;"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import descopeSdk from '@descope/node-sdk';
|
|
2
|
+
import { headers, cookies } from 'next/headers.js';
|
|
2
3
|
import { DESCOPE_SESSION_HEADER } from './constants.js';
|
|
4
|
+
import { getGlobalSdk } from './sdk.js';
|
|
3
5
|
|
|
6
|
+
/* eslint-disable no-console */
|
|
4
7
|
const extractSession = (descopeSession) => {
|
|
5
8
|
if (!descopeSession) {
|
|
6
9
|
return undefined;
|
|
@@ -13,16 +16,40 @@ const extractSession = (descopeSession) => {
|
|
|
13
16
|
return undefined;
|
|
14
17
|
}
|
|
15
18
|
};
|
|
19
|
+
const getSessionFromCookie = async (config) => {
|
|
20
|
+
try {
|
|
21
|
+
const sessionCookie = (await cookies()).get(descopeSdk.SessionTokenCookieName);
|
|
22
|
+
if (!sessionCookie?.value) {
|
|
23
|
+
console.debug('Session cookie not found');
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const sdk = getGlobalSdk(config);
|
|
27
|
+
const res = await sdk.validateJwt(sessionCookie.value);
|
|
28
|
+
return res;
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
console.debug('Error getting session from cookie', err);
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
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
|
+
};
|
|
16
44
|
// returns the session token if it exists in the headers
|
|
17
|
-
|
|
18
|
-
|
|
45
|
+
const session = async (config) => {
|
|
46
|
+
// first attempt to get the session from the headers
|
|
19
47
|
const reqHeaders = await headers();
|
|
20
48
|
const sessionHeader = reqHeaders.get(DESCOPE_SESSION_HEADER);
|
|
21
|
-
return
|
|
49
|
+
return extractOrGetSession(sessionHeader, config);
|
|
22
50
|
};
|
|
23
51
|
// returns the session token if it exists in the request headers
|
|
24
|
-
|
|
25
|
-
const getSession = (req) => extractSession(req.headers[DESCOPE_SESSION_HEADER.toLowerCase()]);
|
|
52
|
+
const getSession = async (req, config) => extractOrGetSession(req.headers[DESCOPE_SESSION_HEADER.toLowerCase()], config);
|
|
26
53
|
|
|
27
54
|
export { getSession, session };
|
|
28
55
|
//# sourceMappingURL=session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"session.js","sources":["../../../src/server/session.ts"],"sourcesContent":["/* eslint-disable no-console */\nimport 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';\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?: CreateSdkParams\n): Promise<AuthenticationInfo | undefined> => {\n\ttry {\n\t\tconst sessionCookie = (await cookies()).get(\n\t\t\tdescopeSdk.SessionTokenCookieName\n\t\t);\n\t\tif (!sessionCookie?.value) {\n\t\t\tconsole.debug('Session cookie not found');\n\t\t\treturn undefined;\n\t\t}\n\t\tconst sdk = getGlobalSdk(config);\n\t\tconst res = await sdk.validateJwt(sessionCookie.value);\n\t\treturn res;\n\t} catch (err) {\n\t\tconsole.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?: CreateSdkParams\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?: CreateSdkParams\n): Promise<AuthenticationInfo | undefined> => {\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?: CreateSdkParams\n): Promise<AuthenticationInfo | undefined> =>\n\textractOrGetSession(\n\t\treq.headers[DESCOPE_SESSION_HEADER.toLowerCase()] as string,\n\t\tconfig\n\t);\n"],"names":[],"mappings":";;;;;AAAA;AAOA,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,MAAwB,KACoB;AAC5C,IAAA,IAAI;AACH,QAAA,MAAM,aAAa,GAAG,CAAC,MAAM,OAAO,EAAE,EAAE,GAAG,CAC1C,UAAU,CAAC,sBAAsB,CACjC,CAAC;AACF,QAAA,IAAI,CAAC,aAAa,EAAE,KAAK,EAAE;AAC1B,YAAA,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC1C,YAAA,OAAO,SAAS,CAAC;SACjB;AACD,QAAA,MAAM,GAAG,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACjC,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;AACvD,QAAA,OAAO,GAAG,CAAC;KACX;IAAC,OAAO,GAAG,EAAE;AACb,QAAA,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAC;AACxD,QAAA,OAAO,SAAS,CAAC;KACjB;AACF,CAAC,CAAC;AAEF;AACA;AACA,MAAM,mBAAmB,GAAG,OAC3B,aAAsB,EACtB,MAAwB,KACoB;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,MAAwB,KACoB;;AAE5C,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,MAAwB,KAExB,mBAAmB,CAClB,GAAG,CAAC,OAAO,CAAC,sBAAsB,CAAC,WAAW,EAAE,CAAW,EAC3D,MAAM;;;;"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import descopeSdk from '@descope/node-sdk';
|
|
2
2
|
type Sdk = ReturnType<typeof descopeSdk>;
|
|
3
|
-
type
|
|
3
|
+
type CreateServerSdkParams = Omit<Parameters<typeof descopeSdk>[0], 'projectId'> & {
|
|
4
4
|
projectId?: string | undefined;
|
|
5
5
|
};
|
|
6
|
-
|
|
7
|
-
export declare const
|
|
8
|
-
export
|
|
6
|
+
type CreateSdkParams = Pick<CreateServerSdkParams, 'projectId' | 'baseUrl'>;
|
|
7
|
+
export declare const createSdk: (config?: CreateServerSdkParams) => Sdk;
|
|
8
|
+
export declare const getGlobalSdk: (config?: CreateSdkParams) => Sdk;
|
|
9
|
+
export type { CreateSdkParams };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AuthenticationInfo } from '@descope/node-sdk';
|
|
2
2
|
import { NextApiRequest } from 'next';
|
|
3
|
-
|
|
4
|
-
export declare const
|
|
3
|
+
import { CreateSdkParams } from './sdk';
|
|
4
|
+
export declare const session: (config?: CreateSdkParams) => Promise<AuthenticationInfo | undefined>;
|
|
5
|
+
export declare const getSession: (req: NextApiRequest, config?: CreateSdkParams) => Promise<AuthenticationInfo | undefined>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@descope/nextjs-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Descope NextJS SDK",
|
|
5
5
|
"author": "Descope Team <info@descope.com>",
|
|
6
6
|
"homepage": "https://github.com/descope/descope-js",
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@descope/node-sdk": "1.6.13",
|
|
67
|
-
"@descope/react-sdk": "2.
|
|
68
|
-
"@descope/
|
|
69
|
-
"@descope/
|
|
67
|
+
"@descope/react-sdk": "2.8.0",
|
|
68
|
+
"@descope/web-component": "3.38.0",
|
|
69
|
+
"@descope/core-js-sdk": "2.37.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@babel/core": "7.26.0",
|