From a1517e50e2c8c4da582c2c87bfb20c4c6e6cdaa9 Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Wed, 2 Oct 2024 17:39:41 +0200 Subject: [PATCH] feat!: separating the OpenId recipe from the Session recipe --- CHANGELOG.md | 93 +++++++++++++++++++ .../oauth2provider/recipeImplementation.js | 13 +-- lib/build/recipe/openid/index.d.ts | 22 ----- lib/build/recipe/openid/index.js | 17 +--- lib/build/recipe/openid/recipe.d.ts | 18 ++-- lib/build/recipe/openid/recipe.js | 42 ++++----- .../recipe/openid/recipeImplementation.d.ts | 9 +- .../recipe/openid/recipeImplementation.js | 16 ++-- lib/build/recipe/openid/types.d.ts | 33 ------- lib/build/recipe/openid/utils.d.ts | 6 +- lib/build/recipe/openid/utils.js | 37 +------- lib/build/recipe/session/index.d.ts | 1 + lib/build/recipe/session/index.js | 17 ++-- lib/build/recipe/session/recipe.d.ts | 8 +- lib/build/recipe/session/recipe.js | 17 +--- .../recipe/session/sessionRequestFunctions.js | 3 +- lib/build/recipe/session/types.d.ts | 42 --------- lib/build/supertokens.js | 20 +++- .../oauth2provider/recipeImplementation.ts | 17 +--- lib/ts/recipe/openid/index.ts | 22 ----- lib/ts/recipe/openid/recipe.ts | 53 ++++------- lib/ts/recipe/openid/recipeImplementation.ts | 48 +++++----- lib/ts/recipe/openid/types.ts | 34 ------- lib/ts/recipe/openid/utils.ts | 22 +---- lib/ts/recipe/session/index.ts | 11 ++- lib/ts/recipe/session/recipe.ts | 25 ++--- .../recipe/session/sessionRequestFunctions.ts | 3 +- lib/ts/recipe/session/types.ts | 42 --------- lib/ts/supertokens.ts | 20 +++- recipe/openid/index.d.ts | 10 ++ recipe/openid/index.js | 6 ++ recipe/openid/types/index.d.ts | 10 ++ recipe/openid/types/index.js | 6 ++ test/openid/config.test.js | 61 ++++-------- test/openid/openid.test.js | 14 ++- test/with-typescript/index.ts | 62 ++++++------- 36 files changed, 338 insertions(+), 542 deletions(-) create mode 100644 recipe/openid/index.d.ts create mode 100644 recipe/openid/index.js create mode 100644 recipe/openid/types/index.d.ts create mode 100644 recipe/openid/types/index.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 069ae262e..a5e1f2d63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,99 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - subject_types_supported - id_token_signing_alg_values_supported - response_types_supported +- Exposing the OpenId recipe separately and remove it from the Session recipe + - This means that we removed `override.openIdFeature` from the Session recipe configuration +- Removed `getJWKS` from the OpenId recipe, as it is already exposed by the JWT recipe +- We now automatically initialize the OpenId and JWT recipes even if you do not use the Session recipe + +### Migration + +#### Separating the OpenId recipe from Session recipe + +If you used to use the `openIdFeature` in the Session recipe, you should now use the OpenId recipe directly instead: + +Before: + +```tsx +import SuperTokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "...", + }, + recipeList: [ + Session.init({ + override: { + openIdFeature: { + jwtFeature: { + functions: originalImplementation => ({ + ...originalImplementation, + getJWKS: async (input) => { + console.log("getJWKS called"); + return originalImplementation.getJWKS(input); + }, + }) + }, + functions: originalImplementation => ({ + ...originalImplementation, + getOpenIdDiscoveryConfiguration: async (input) => ({ + issuer: "your issuer", + jwks_uri: "https://your.api.domain/auth/jwt/jwks.json", + status: "OK" + }), + }) + } + } + }); + ], +}); +``` + +After: + +```tsx +import SuperTokens from "supertokens-node"; +import Session from "supertokens-node/recipe/session"; +import OpenId from "supertokens-node/recipe/openid"; +import JWT from "supertokens-node/recipe/jwt"; + +SuperTokens.init({ + appInfo: { + apiDomain: "...", + appName: "...", + websiteDomain: "...", + }, + recipeList: [ + Session.init(), + JWT.init({ + override: { + functions: originalImplementation => ({ + ...originalImplementation, + getJWKS: async (input) => { + console.log("getJWKS called"); + return originalImplementation.getJWKS(input); + }, + }) + } + }), + OpenId.init({ + override: { + functions: originalImplementation => ({ + ...originalImplementation, + getOpenIdDiscoveryConfiguration: async (input) => ({ + issuer: "your issuer", + jwks_uri: "https://your.api.domain/auth/jwt/jwks.json", + status: "OK" + }), + }) + } + }); + ], +}); +``` ## [20.1.3] - 2024-09-30 diff --git a/lib/build/recipe/oauth2provider/recipeImplementation.js b/lib/build/recipe/oauth2provider/recipeImplementation.js index 8725c2363..cde274874 100644 --- a/lib/build/recipe/oauth2provider/recipeImplementation.js +++ b/lib/build/recipe/oauth2provider/recipeImplementation.js @@ -61,6 +61,7 @@ const OAuth2Client_1 = require("./OAuth2Client"); const __1 = require("../.."); const combinedRemoteJWKSet_1 = require("../../combinedRemoteJWKSet"); const recipe_1 = __importDefault(require("../session/recipe")); +const recipe_2 = __importDefault(require("../openid/recipe")); const constants_1 = require("../multitenancy/constants"); function getUpdatedRedirectTo(appInfo, redirectTo) { return redirectTo.replace( @@ -177,7 +178,7 @@ function getRecipeInterface( grantAccessTokenAudience: input.grantAccessTokenAudience, grantScope: input.grantScope, handledAt: input.handledAt, - iss: await getIssuer(input.userContext), + iss: await recipe_2.default.getIssuer(input.userContext), tId: input.tenantId, rsub: input.rsub, sessionHandle: input.sessionHandle, @@ -348,7 +349,7 @@ function getRecipeInterface( inputBody: input.body, authorizationHeader: input.authorizationHeader, }; - body.iss = await getIssuer(input.userContext); + body.iss = await recipe_2.default.getIssuer(input.userContext); if (input.body.grant_type === "password") { return { status: "ERROR", @@ -842,11 +843,3 @@ function getRecipeInterface( }; } exports.default = getRecipeInterface; -async function getIssuer(userContext) { - // We already depend on the Session recipe being initialized elsewhere in this recipe - const openIdConfig = await recipe_1.default - .getInstanceOrThrowError() - .openIdRecipe.recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext }); - // We grab it from the openIdConfig because that is the way we used to tell people to override - return openIdConfig.issuer; -} diff --git a/lib/build/recipe/openid/index.d.ts b/lib/build/recipe/openid/index.d.ts index e67e3d8a4..84b55bd8c 100644 --- a/lib/build/recipe/openid/index.d.ts +++ b/lib/build/recipe/openid/index.d.ts @@ -18,28 +18,6 @@ export default class OpenIdRecipeWrapper { id_token_signing_alg_values_supported: string[]; response_types_supported: string[]; }>; - static createJWT( - payload?: any, - validitySeconds?: number, - useStaticSigningKey?: boolean, - userContext?: Record - ): Promise< - | { - status: "OK"; - jwt: string; - } - | { - status: "UNSUPPORTED_ALGORITHM_ERROR"; - } - >; - static getJWKS( - userContext?: Record - ): Promise<{ - keys: import("../jwt").JsonWebKey[]; - validityInSeconds?: number | undefined; - }>; } export declare let init: typeof OpenIdRecipe.init; export declare let getOpenIdDiscoveryConfiguration: typeof OpenIdRecipeWrapper.getOpenIdDiscoveryConfiguration; -export declare let createJWT: typeof OpenIdRecipeWrapper.createJWT; -export declare let getJWKS: typeof OpenIdRecipeWrapper.getJWKS; diff --git a/lib/build/recipe/openid/index.js b/lib/build/recipe/openid/index.js index 7fe6c9681..227ea73f7 100644 --- a/lib/build/recipe/openid/index.js +++ b/lib/build/recipe/openid/index.js @@ -5,7 +5,7 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getJWKS = exports.createJWT = exports.getOpenIdDiscoveryConfiguration = exports.init = void 0; +exports.getOpenIdDiscoveryConfiguration = exports.init = void 0; const utils_1 = require("../../utils"); const recipe_1 = __importDefault(require("./recipe")); class OpenIdRecipeWrapper { @@ -14,23 +14,8 @@ class OpenIdRecipeWrapper { userContext: utils_1.getUserContext(userContext), }); } - static createJWT(payload, validitySeconds, useStaticSigningKey, userContext) { - return recipe_1.default.getInstanceOrThrowError().jwtRecipe.recipeInterfaceImpl.createJWT({ - payload, - validitySeconds, - useStaticSigningKey, - userContext: utils_1.getUserContext(userContext), - }); - } - static getJWKS(userContext) { - return recipe_1.default.getInstanceOrThrowError().jwtRecipe.recipeInterfaceImpl.getJWKS({ - userContext: utils_1.getUserContext(userContext), - }); - } } exports.default = OpenIdRecipeWrapper; OpenIdRecipeWrapper.init = recipe_1.default.init; exports.init = OpenIdRecipeWrapper.init; exports.getOpenIdDiscoveryConfiguration = OpenIdRecipeWrapper.getOpenIdDiscoveryConfiguration; -exports.createJWT = OpenIdRecipeWrapper.createJWT; -exports.getJWKS = OpenIdRecipeWrapper.getJWKS; diff --git a/lib/build/recipe/openid/recipe.d.ts b/lib/build/recipe/openid/recipe.d.ts index 8091cb365..cac8551d3 100644 --- a/lib/build/recipe/openid/recipe.d.ts +++ b/lib/build/recipe/openid/recipe.d.ts @@ -5,34 +5,28 @@ import normalisedURLPath from "../../normalisedURLPath"; import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; -import JWTRecipe from "../jwt/recipe"; export default class OpenIdRecipe extends RecipeModule { static RECIPE_ID: string; private static instance; config: TypeNormalisedInput; - jwtRecipe: JWTRecipe; recipeImplementation: RecipeInterface; apiImpl: APIInterface; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); + constructor(recipeId: string, appInfo: NormalisedAppinfo, config?: TypeInput); static getInstanceOrThrowError(): OpenIdRecipe; static init(config?: TypeInput): RecipeListFunction; static reset(): void; + static getIssuer(userContext: UserContext): Promise; getAPIsHandled: () => APIHandled[]; handleAPIRequest: ( id: string, - tenantId: string, + _tenantId: string, req: BaseRequest, response: BaseResponse, - path: normalisedURLPath, - method: HTTPMethod, + _path: normalisedURLPath, + _method: HTTPMethod, userContext: UserContext ) => Promise; - handleError: ( - error: STError, - request: BaseRequest, - response: BaseResponse, - userContext: UserContext - ) => Promise; + handleError: (error: STError) => Promise; getAllCORSHeaders: () => string[]; isErrorFromThisRecipe: (err: any) => err is STError; } diff --git a/lib/build/recipe/openid/recipe.js b/lib/build/recipe/openid/recipe.js index 9528e93d9..ab6336364 100644 --- a/lib/build/recipe/openid/recipe.js +++ b/lib/build/recipe/openid/recipe.js @@ -22,7 +22,6 @@ Object.defineProperty(exports, "__esModule", { value: true }); const error_1 = __importDefault(require("../../error")); const recipeModule_1 = __importDefault(require("../../recipeModule")); const utils_1 = require("./utils"); -const recipe_1 = __importDefault(require("../jwt/recipe")); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); const recipeImplementation_1 = __importDefault(require("./recipeImplementation")); const implementation_1 = __importDefault(require("./api/implementation")); @@ -31,7 +30,7 @@ const constants_1 = require("./constants"); const getOpenIdDiscoveryConfiguration_1 = __importDefault(require("./api/getOpenIdDiscoveryConfiguration")); const utils_2 = require("../../utils"); class OpenIdRecipe extends recipeModule_1.default { - constructor(recipeId, appInfo, isInServerlessEnv, config) { + constructor(recipeId, appInfo, config) { super(recipeId, appInfo); this.getAPIsHandled = () => { return [ @@ -41,10 +40,9 @@ class OpenIdRecipe extends recipeModule_1.default { id: constants_1.GET_DISCOVERY_CONFIG_URL, disabled: this.apiImpl.getOpenIdDiscoveryConfigurationGET === undefined, }, - ...this.jwtRecipe.getAPIsHandled(), ]; }; - this.handleAPIRequest = async (id, tenantId, req, response, path, method, userContext) => { + this.handleAPIRequest = async (id, _tenantId, req, response, _path, _method, userContext) => { let apiOptions = { recipeImplementation: this.recipeImplementation, config: this.config, @@ -55,33 +53,20 @@ class OpenIdRecipe extends recipeModule_1.default { if (id === constants_1.GET_DISCOVERY_CONFIG_URL) { return await getOpenIdDiscoveryConfiguration_1.default(this.apiImpl, apiOptions, userContext); } else { - return this.jwtRecipe.handleAPIRequest(id, tenantId, req, response, path, method, userContext); + return false; } }; - this.handleError = async (error, request, response, userContext) => { - if (error.fromRecipe === OpenIdRecipe.RECIPE_ID) { - throw error; - } else { - return await this.jwtRecipe.handleError(error, request, response, userContext); - } + this.handleError = async (error) => { + throw error; }; this.getAllCORSHeaders = () => { - return [...this.jwtRecipe.getAllCORSHeaders()]; + return []; }; this.isErrorFromThisRecipe = (err) => { - return ( - (error_1.default.isErrorFromSuperTokens(err) && err.fromRecipe === OpenIdRecipe.RECIPE_ID) || - this.jwtRecipe.isErrorFromThisRecipe(err) - ); + return error_1.default.isErrorFromSuperTokens(err) && err.fromRecipe === OpenIdRecipe.RECIPE_ID; }; - this.config = utils_1.validateAndNormaliseUserInput(appInfo, config); - this.jwtRecipe = new recipe_1.default(recipeId, appInfo, isInServerlessEnv, { - jwtValiditySeconds: this.config.jwtValiditySeconds, - override: this.config.override.jwtFeature, - }); - let builder = new supertokens_js_override_1.default( - recipeImplementation_1.default(this.config, this.jwtRecipe.recipeInterfaceImpl, appInfo) - ); + this.config = utils_1.validateAndNormaliseUserInput(config); + let builder = new supertokens_js_override_1.default(recipeImplementation_1.default(appInfo)); this.recipeImplementation = builder.override(this.config.override.functions).build(); let apiBuilder = new supertokens_js_override_1.default(implementation_1.default()); this.apiImpl = apiBuilder.override(this.config.override.apis).build(); @@ -93,9 +78,9 @@ class OpenIdRecipe extends recipeModule_1.default { throw new Error("Initialisation not done. Did you forget to call the Openid.init function?"); } static init(config) { - return (appInfo, isInServerlessEnv) => { + return (appInfo) => { if (OpenIdRecipe.instance === undefined) { - OpenIdRecipe.instance = new OpenIdRecipe(OpenIdRecipe.RECIPE_ID, appInfo, isInServerlessEnv, config); + OpenIdRecipe.instance = new OpenIdRecipe(OpenIdRecipe.RECIPE_ID, appInfo, config); return OpenIdRecipe.instance; } else { throw new Error("OpenId recipe has already been initialised. Please check your code for bugs."); @@ -108,6 +93,11 @@ class OpenIdRecipe extends recipeModule_1.default { } OpenIdRecipe.instance = undefined; } + static async getIssuer(userContext) { + return ( + await this.getInstanceOrThrowError().recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext }) + ).issuer; + } } exports.default = OpenIdRecipe; OpenIdRecipe.RECIPE_ID = "openid"; diff --git a/lib/build/recipe/openid/recipeImplementation.d.ts b/lib/build/recipe/openid/recipeImplementation.d.ts index be9ecbb29..07ebf044c 100644 --- a/lib/build/recipe/openid/recipeImplementation.d.ts +++ b/lib/build/recipe/openid/recipeImplementation.d.ts @@ -1,9 +1,4 @@ // @ts-nocheck -import { RecipeInterface, TypeNormalisedInput } from "./types"; -import { RecipeInterface as JWTRecipeInterface } from "../jwt/types"; +import { RecipeInterface } from "./types"; import { NormalisedAppinfo } from "../../types"; -export default function getRecipeInterface( - config: TypeNormalisedInput, - jwtRecipeImplementation: JWTRecipeInterface, - appInfo: NormalisedAppinfo -): RecipeInterface; +export default function getRecipeInterface(appInfo: NormalisedAppinfo): RecipeInterface; diff --git a/lib/build/recipe/openid/recipeImplementation.js b/lib/build/recipe/openid/recipeImplementation.js index cd7e37bb7..746c52a35 100644 --- a/lib/build/recipe/openid/recipeImplementation.js +++ b/lib/build/recipe/openid/recipeImplementation.js @@ -5,16 +5,17 @@ var __importDefault = return mod && mod.__esModule ? mod : { default: mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +const recipe_1 = __importDefault(require("../jwt/recipe")); const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); const constants_1 = require("../jwt/constants"); const constants_2 = require("../oauth2provider/constants"); -function getRecipeInterface(config, jwtRecipeImplementation, appInfo) { +function getRecipeInterface(appInfo) { return { getOpenIdDiscoveryConfiguration: async function () { - let issuer = config.issuerDomain.getAsStringDangerous() + config.issuerPath.getAsStringDangerous(); + let issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); let jwks_uri = - config.issuerDomain.getAsStringDangerous() + - config.issuerPath + appInfo.apiDomain.getAsStringDangerous() + + appInfo.apiBasePath .appendPath(new normalisedURLPath_1.default(constants_1.GET_JWKS_API)) .getAsStringDangerous(); const apiBasePath = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); @@ -35,17 +36,14 @@ function getRecipeInterface(config, jwtRecipeImplementation, appInfo) { }, createJWT: async function ({ payload, validitySeconds, useStaticSigningKey, userContext }) { payload = payload === undefined || payload === null ? {} : payload; - let issuer = config.issuerDomain.getAsStringDangerous() + config.issuerPath.getAsStringDangerous(); - return await jwtRecipeImplementation.createJWT({ + let issuer = (await this.getOpenIdDiscoveryConfiguration({ userContext })).issuer; + return await recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.createJWT({ payload: Object.assign({ iss: issuer }, payload), useStaticSigningKey, validitySeconds, userContext, }); }, - getJWKS: async function (input) { - return await jwtRecipeImplementation.getJWKS(input); - }, }; } exports.default = getRecipeInterface; diff --git a/lib/build/recipe/openid/types.d.ts b/lib/build/recipe/openid/types.d.ts index 6af18db9d..b0dda95fd 100644 --- a/lib/build/recipe/openid/types.d.ts +++ b/lib/build/recipe/openid/types.d.ts @@ -1,51 +1,23 @@ // @ts-nocheck import OverrideableBuilder from "supertokens-js-override"; import type { BaseRequest, BaseResponse } from "../../framework"; -import NormalisedURLDomain from "../../normalisedURLDomain"; -import NormalisedURLPath from "../../normalisedURLPath"; -import { RecipeInterface as JWTRecipeInterface, APIInterface as JWTAPIInterface, JsonWebKey } from "../jwt/types"; import { GeneralErrorResponse, UserContext } from "../../types"; export declare type TypeInput = { - issuer?: string; - jwtValiditySeconds?: number; override?: { functions?: ( originalImplementation: RecipeInterface, builder?: OverrideableBuilder ) => RecipeInterface; apis?: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; }; }; export declare type TypeNormalisedInput = { - issuerDomain: NormalisedURLDomain; - issuerPath: NormalisedURLPath; - jwtValiditySeconds?: number; override: { functions: ( originalImplementation: RecipeInterface, builder?: OverrideableBuilder ) => RecipeInterface; apis: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; }; }; export declare type APIOptions = { @@ -110,9 +82,4 @@ export declare type RecipeInterface = { status: "UNSUPPORTED_ALGORITHM_ERROR"; } >; - getJWKS(input: { - userContext: UserContext; - }): Promise<{ - keys: JsonWebKey[]; - }>; }; diff --git a/lib/build/recipe/openid/utils.d.ts b/lib/build/recipe/openid/utils.d.ts index 6b5abd280..0cc991d9a 100644 --- a/lib/build/recipe/openid/utils.d.ts +++ b/lib/build/recipe/openid/utils.d.ts @@ -1,7 +1,3 @@ // @ts-nocheck -import { NormalisedAppinfo } from "../../types"; import { TypeInput, TypeNormalisedInput } from "./types"; -export declare function validateAndNormaliseUserInput( - appInfo: NormalisedAppinfo, - config?: TypeInput -): TypeNormalisedInput; +export declare function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalisedInput; diff --git a/lib/build/recipe/openid/utils.js b/lib/build/recipe/openid/utils.js index fac3a3f43..ad70f404c 100644 --- a/lib/build/recipe/openid/utils.js +++ b/lib/build/recipe/openid/utils.js @@ -1,39 +1,7 @@ "use strict"; -var __importDefault = - (this && this.__importDefault) || - function (mod) { - return mod && mod.__esModule ? mod : { default: mod }; - }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateAndNormaliseUserInput = void 0; -/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. - * - * This software is licensed under the Apache License, Version 2.0 (the - * "License") as published by the Apache Software Foundation. - * - * You may not use this file except in compliance with the License. You may - * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -const normalisedURLDomain_1 = __importDefault(require("../../normalisedURLDomain")); -const normalisedURLPath_1 = __importDefault(require("../../normalisedURLPath")); -function validateAndNormaliseUserInput(appInfo, config) { - let issuerDomain = appInfo.apiDomain; - let issuerPath = appInfo.apiBasePath; - if (config !== undefined) { - if (config.issuer !== undefined) { - issuerDomain = new normalisedURLDomain_1.default(config.issuer); - issuerPath = new normalisedURLPath_1.default(config.issuer); - } - if (!issuerPath.equals(appInfo.apiBasePath)) { - throw new Error("The path of the issuer URL must be equal to the apiBasePath. The default value is /auth"); - } - } +function validateAndNormaliseUserInput(config) { let override = Object.assign( { functions: (originalImplementation) => originalImplementation, @@ -42,9 +10,6 @@ function validateAndNormaliseUserInput(appInfo, config) { config === null || config === void 0 ? void 0 : config.override ); return { - issuerDomain, - issuerPath, - jwtValiditySeconds: config === null || config === void 0 ? void 0 : config.jwtValiditySeconds, override, }; } diff --git a/lib/build/recipe/session/index.d.ts b/lib/build/recipe/session/index.d.ts index d4cb6414b..8115d4727 100644 --- a/lib/build/recipe/session/index.d.ts +++ b/lib/build/recipe/session/index.d.ts @@ -170,6 +170,7 @@ export default class SessionWrapper { userContext?: Record ): Promise<{ keys: import("../jwt").JsonWebKey[]; + validityInSeconds?: number | undefined; }>; static getOpenIdDiscoveryConfiguration( userContext?: Record diff --git a/lib/build/recipe/session/index.js b/lib/build/recipe/session/index.js index 63f8d33be..eebfd546a 100644 --- a/lib/build/recipe/session/index.js +++ b/lib/build/recipe/session/index.js @@ -22,6 +22,8 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.getOpenIdDiscoveryConfiguration = exports.getJWKS = exports.createJWT = exports.Error = exports.validateClaimsForSessionHandle = exports.removeClaim = exports.getClaimValue = exports.setClaimValue = exports.fetchAndSetClaim = exports.mergeIntoAccessTokenPayload = exports.updateSessionDataInDatabase = exports.revokeMultipleSessions = exports.revokeSession = exports.getAllSessionHandlesForUser = exports.revokeAllSessionsForUser = exports.refreshSessionWithoutRequestResponse = exports.refreshSession = exports.getSessionInformation = exports.getSessionWithoutRequestResponse = exports.getSession = exports.createNewSessionWithoutRequestResponse = exports.createNewSession = exports.init = void 0; const error_1 = __importDefault(require("./error")); const recipe_1 = __importDefault(require("./recipe")); +const recipe_2 = __importDefault(require("../openid/recipe")); +const recipe_3 = __importDefault(require("../jwt/recipe")); const utils_1 = require("./utils"); const sessionRequestFunctions_1 = require("./sessionRequestFunctions"); const __1 = require("../.."); @@ -71,8 +73,7 @@ class SessionWrapper { const ctx = utils_2.getUserContext(userContext); const recipeInstance = recipe_1.default.getInstanceOrThrowError(); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const appInfo = recipeInstance.getAppInfo(); - const issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); + const issuer = await recipe_2.default.getIssuer(ctx); let finalAccessTokenPayload = Object.assign(Object.assign({}, accessTokenPayload), { iss: issuer }); for (const prop of constants_2.protectedProps) { delete finalAccessTokenPayload[prop]; @@ -249,7 +250,7 @@ class SessionWrapper { }); } static createJWT(payload, validitySeconds, useStaticSigningKey, userContext) { - return recipe_1.default.getInstanceOrThrowError().openIdRecipe.recipeImplementation.createJWT({ + return recipe_2.default.getInstanceOrThrowError().recipeImplementation.createJWT({ payload, validitySeconds, useStaticSigningKey, @@ -257,16 +258,14 @@ class SessionWrapper { }); } static getJWKS(userContext) { - return recipe_1.default.getInstanceOrThrowError().openIdRecipe.recipeImplementation.getJWKS({ + return recipe_3.default.getInstanceOrThrowError().recipeInterfaceImpl.getJWKS({ userContext: utils_2.getUserContext(userContext), }); } static getOpenIdDiscoveryConfiguration(userContext) { - return recipe_1.default - .getInstanceOrThrowError() - .openIdRecipe.recipeImplementation.getOpenIdDiscoveryConfiguration({ - userContext: utils_2.getUserContext(userContext), - }); + return recipe_2.default.getInstanceOrThrowError().recipeImplementation.getOpenIdDiscoveryConfiguration({ + userContext: utils_2.getUserContext(userContext), + }); } static fetchAndSetClaim(sessionHandle, claim, userContext) { return recipe_1.default.getInstanceOrThrowError().recipeInterfaceImpl.fetchAndSetClaim({ diff --git a/lib/build/recipe/session/recipe.d.ts b/lib/build/recipe/session/recipe.d.ts index b0fca4a4e..ecb163142 100644 --- a/lib/build/recipe/session/recipe.d.ts +++ b/lib/build/recipe/session/recipe.d.ts @@ -13,7 +13,6 @@ import STError from "./error"; import { NormalisedAppinfo, RecipeListFunction, APIHandled, HTTPMethod, UserContext } from "../../types"; import NormalisedURLPath from "../../normalisedURLPath"; import type { BaseRequest, BaseResponse } from "../../framework"; -import OpenIdRecipe from "../openid/recipe"; export default class SessionRecipe extends RecipeModule { private static instance; static RECIPE_ID: string; @@ -21,7 +20,6 @@ export default class SessionRecipe extends RecipeModule { private claimValidatorsAddedByOtherRecipes; config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; - openIdRecipe: OpenIdRecipe; apiImpl: APIInterface; isInServerlessEnv: boolean; constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput); @@ -35,11 +33,11 @@ export default class SessionRecipe extends RecipeModule { getAPIsHandled: () => APIHandled[]; handleAPIRequest: ( id: string, - tenantId: string, + _tenantId: string, req: BaseRequest, res: BaseResponse, - path: NormalisedURLPath, - method: HTTPMethod, + _path: NormalisedURLPath, + _method: HTTPMethod, userContext: UserContext ) => Promise; handleError: ( diff --git a/lib/build/recipe/session/recipe.js b/lib/build/recipe/session/recipe.js index e43b86da0..fcec65ac9 100644 --- a/lib/build/recipe/session/recipe.js +++ b/lib/build/recipe/session/recipe.js @@ -31,7 +31,6 @@ const recipeImplementation_1 = __importDefault(require("./recipeImplementation") const querier_1 = require("../../querier"); const implementation_1 = __importDefault(require("./api/implementation")); const supertokens_js_override_1 = __importDefault(require("supertokens-js-override")); -const recipe_1 = __importDefault(require("../openid/recipe")); const logger_1 = require("../../logger"); const combinedRemoteJWKSet_1 = require("../../combinedRemoteJWKSet"); const utils_2 = require("../../utils"); @@ -75,10 +74,9 @@ class SessionRecipe extends recipeModule_1.default { disabled: this.apiImpl.signOutPOST === undefined, }, ]; - apisHandled.push(...this.openIdRecipe.getAPIsHandled()); return apisHandled; }; - this.handleAPIRequest = async (id, tenantId, req, res, path, method, userContext) => { + this.handleAPIRequest = async (id, _tenantId, req, res, _path, _method, userContext) => { let options = { config: this.config, recipeId: this.getRecipeId(), @@ -92,7 +90,7 @@ class SessionRecipe extends recipeModule_1.default { } else if (id === constants_1.SIGNOUT_API_PATH) { return await signout_1.default(this.apiImpl, options, userContext); } else { - return await this.openIdRecipe.handleAPIRequest(id, tenantId, req, res, path, method, userContext); + return false; } }; this.handleError = async (err, request, response, userContext) => { @@ -156,19 +154,15 @@ class SessionRecipe extends recipeModule_1.default { throw err; } } else { - return await this.openIdRecipe.handleError(err, request, response, userContext); + throw err; } }; this.getAllCORSHeaders = () => { let corsHeaders = [...cookieAndHeaders_1.getCORSAllowedHeaders()]; - corsHeaders.push(...this.openIdRecipe.getAllCORSHeaders()); return corsHeaders; }; this.isErrorFromThisRecipe = (err) => { - return ( - error_1.default.isErrorFromSuperTokens(err) && - (err.fromRecipe === SessionRecipe.RECIPE_ID || this.openIdRecipe.isErrorFromThisRecipe(err)) - ); + return error_1.default.isErrorFromSuperTokens(err) && err.fromRecipe === SessionRecipe.RECIPE_ID; }; this.verifySession = async (options, request, response, userContext) => { return await this.apiImpl.verifySession({ @@ -208,9 +202,6 @@ class SessionRecipe extends recipeModule_1.default { ); logger_1.logDebugMessage("session init: sessionExpiredStatusCode: " + this.config.sessionExpiredStatusCode); this.isInServerlessEnv = isInServerlessEnv; - this.openIdRecipe = new recipe_1.default(recipeId, appInfo, isInServerlessEnv, { - override: this.config.override.openIdFeature, - }); let builder = new supertokens_js_override_1.default( recipeImplementation_1.default( querier_1.Querier.getNewInstanceOrThrowError(recipeId), diff --git a/lib/build/recipe/session/sessionRequestFunctions.js b/lib/build/recipe/session/sessionRequestFunctions.js index ea6c2819f..df0a56f0e 100644 --- a/lib/build/recipe/session/sessionRequestFunctions.js +++ b/lib/build/recipe/session/sessionRequestFunctions.js @@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.createNewSessionInRequest = exports.refreshSessionInRequest = exports.getAccessTokenFromRequest = exports.getSessionFromRequest = void 0; const framework_1 = __importDefault(require("../../framework")); const supertokens_1 = __importDefault(require("../../supertokens")); +const recipe_1 = __importDefault(require("../openid/recipe")); const utils_1 = require("./utils"); const utils_2 = require("../../utils"); const logger_1 = require("../../logger"); @@ -383,7 +384,7 @@ async function createNewSessionInRequest({ logger_1.logDebugMessage("createNewSession: Wrapping done"); userContext = utils_2.setRequestInUserContextIfNotDefined(userContext, req); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); + const issuer = await recipe_1.default.getIssuer(userContext); let finalAccessTokenPayload = Object.assign(Object.assign({}, accessTokenPayload), { iss: issuer }); for (const prop of constants_1.protectedProps) { delete finalAccessTokenPayload[prop]; diff --git a/lib/build/recipe/session/types.d.ts b/lib/build/recipe/session/types.d.ts index e19381b3f..b573925ed 100644 --- a/lib/build/recipe/session/types.d.ts +++ b/lib/build/recipe/session/types.d.ts @@ -1,9 +1,7 @@ // @ts-nocheck import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; -import { RecipeInterface as JWTRecipeInterface, APIInterface as JWTAPIInterface } from "../jwt/types"; import OverrideableBuilder from "supertokens-js-override"; -import { RecipeInterface as OpenIdRecipeInterface, APIInterface as OpenIdAPIInterface } from "../openid/types"; import { JSONObject, JSONValue, UserContext } from "../../types"; import { GeneralErrorResponse } from "../../types"; import RecipeUserId from "../../recipeUserId"; @@ -64,26 +62,6 @@ export declare type TypeInput = { builder?: OverrideableBuilder ) => RecipeInterface; apis?: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - openIdFeature?: { - functions?: ( - originalImplementation: OpenIdRecipeInterface, - builder?: OverrideableBuilder - ) => OpenIdRecipeInterface; - apis?: ( - originalImplementation: OpenIdAPIInterface, - builder?: OverrideableBuilder - ) => OpenIdAPIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; - }; }; }; export declare type TypeNormalisedInput = { @@ -119,26 +97,6 @@ export declare type TypeNormalisedInput = { builder?: OverrideableBuilder ) => RecipeInterface; apis: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - openIdFeature?: { - functions?: ( - originalImplementation: OpenIdRecipeInterface, - builder?: OverrideableBuilder - ) => OpenIdRecipeInterface; - apis?: ( - originalImplementation: OpenIdAPIInterface, - builder?: OverrideableBuilder - ) => OpenIdAPIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; - }; }; }; export interface SessionRequest extends BaseRequest { diff --git a/lib/build/supertokens.js b/lib/build/supertokens.js index 4c3462392..db7ceb9ef 100644 --- a/lib/build/supertokens.js +++ b/lib/build/supertokens.js @@ -377,6 +377,8 @@ class SuperTokens { let userMetadataFound = false; let multiFactorAuthFound = false; let oauth2Found = false; + let openIdFound = false; + let jwtFound = false; // Multitenancy recipe is an always initialized recipe and needs to be imported this way // so that there is no circular dependency. Otherwise there would be cyclic dependency // between `supertokens.ts` -> `recipeModule.ts` -> `multitenancy/recipe.ts` @@ -385,6 +387,8 @@ class SuperTokens { let MultiFactorAuthRecipe = require("./recipe/multifactorauth/recipe").default; let TotpRecipe = require("./recipe/totp/recipe").default; let OAuth2ProviderRecipe = require("./recipe/oauth2provider/recipe").default; + let OpenIdRecipe = require("./recipe/openid/recipe").default; + let jwtRecipe = require("./recipe/jwt/recipe").default; this.recipeModules = config.recipeList.map((func) => { const recipeModule = func(this.appInfo, this.isInServerlessEnv); if (recipeModule.getRecipeId() === MultitenancyRecipe.RECIPE_ID) { @@ -397,9 +401,19 @@ class SuperTokens { totpFound = true; } else if (recipeModule.getRecipeId() === OAuth2ProviderRecipe.RECIPE_ID) { oauth2Found = true; + } else if (recipeModule.getRecipeId() === OpenIdRecipe.RECIPE_ID) { + openIdFound = true; + } else if (recipeModule.getRecipeId() === jwtRecipe.RECIPE_ID) { + jwtFound = true; } return recipeModule; }); + if (!jwtFound) { + this.recipeModules.push(jwtRecipe.init()(this.appInfo, this.isInServerlessEnv)); + } + if (!openIdFound) { + this.recipeModules.push(OpenIdRecipe.init()(this.appInfo, this.isInServerlessEnv)); + } if (!multitenancyFound) { this.recipeModules.push(MultitenancyRecipe.init()(this.appInfo, this.isInServerlessEnv)); } @@ -431,11 +445,15 @@ class SuperTokens { if (!utils_1.isTestEnv()) { throw new Error("calling testing function in non testing env"); } - // We call reset the OAuth2Provider recipe because it is auto-initialized + // We call reset the following recipes because they are auto-initialized // and there is no case where we want to reset the SuperTokens instance but not // the recipes. let OAuth2ProviderRecipe = require("./recipe/oauth2provider/recipe").default; OAuth2ProviderRecipe.reset(); + let OpenIdRecipe = require("./recipe/openid/recipe").default; + OpenIdRecipe.reset(); + let JWTRecipe = require("./recipe/jwt/recipe").default; + JWTRecipe.reset(); querier_1.Querier.reset(); SuperTokens.instance = undefined; } diff --git a/lib/ts/recipe/oauth2provider/recipeImplementation.ts b/lib/ts/recipe/oauth2provider/recipeImplementation.ts index e6effbeeb..2e7a62e43 100644 --- a/lib/ts/recipe/oauth2provider/recipeImplementation.ts +++ b/lib/ts/recipe/oauth2provider/recipeImplementation.ts @@ -16,7 +16,7 @@ import * as jose from "jose"; import NormalisedURLPath from "../../normalisedURLPath"; import { Querier } from "../../querier"; -import { JSONObject, NormalisedAppinfo, UserContext } from "../../types"; +import { JSONObject, NormalisedAppinfo } from "../../types"; import { RecipeInterface, TypeNormalisedInput, @@ -28,6 +28,7 @@ import { OAuth2Client } from "./OAuth2Client"; import { getUser } from "../.."; import { getCombinedJWKS } from "../../combinedRemoteJWKSet"; import SessionRecipe from "../session/recipe"; +import OpenIdRecipe from "../openid/recipe"; import { DEFAULT_TENANT_ID } from "../multitenancy/constants"; function getUpdatedRedirectTo(appInfo: NormalisedAppinfo, redirectTo: string) { @@ -153,7 +154,7 @@ export default function getRecipeInterface( grantAccessTokenAudience: input.grantAccessTokenAudience, grantScope: input.grantScope, handledAt: input.handledAt, - iss: await getIssuer(input.userContext), + iss: await OpenIdRecipe.getIssuer(input.userContext), tId: input.tenantId, rsub: input.rsub, sessionHandle: input.sessionHandle, @@ -340,7 +341,7 @@ export default function getRecipeInterface( authorizationHeader: input.authorizationHeader, }; - body.iss = await getIssuer(input.userContext); + body.iss = await OpenIdRecipe.getIssuer(input.userContext); if (input.body.grant_type === "password") { return { @@ -863,13 +864,3 @@ export default function getRecipeInterface( }, }; } - -async function getIssuer(userContext: UserContext) { - // We already depend on the Session recipe being initialized elsewhere in this recipe - const openIdConfig = await SessionRecipe.getInstanceOrThrowError().openIdRecipe.recipeImplementation.getOpenIdDiscoveryConfiguration( - { userContext } - ); - // We grab it from the openIdConfig because that is the way we used to tell people to override - - return openIdConfig.issuer; -} diff --git a/lib/ts/recipe/openid/index.ts b/lib/ts/recipe/openid/index.ts index cf69bc4b6..926e2e98b 100644 --- a/lib/ts/recipe/openid/index.ts +++ b/lib/ts/recipe/openid/index.ts @@ -9,29 +9,7 @@ export default class OpenIdRecipeWrapper { userContext: getUserContext(userContext), }); } - - static createJWT( - payload?: any, - validitySeconds?: number, - useStaticSigningKey?: boolean, - userContext?: Record - ) { - return OpenIdRecipe.getInstanceOrThrowError().jwtRecipe.recipeInterfaceImpl.createJWT({ - payload, - validitySeconds, - useStaticSigningKey, - userContext: getUserContext(userContext), - }); - } - - static getJWKS(userContext?: Record) { - return OpenIdRecipe.getInstanceOrThrowError().jwtRecipe.recipeInterfaceImpl.getJWKS({ - userContext: getUserContext(userContext), - }); - } } export let init = OpenIdRecipeWrapper.init; export let getOpenIdDiscoveryConfiguration = OpenIdRecipeWrapper.getOpenIdDiscoveryConfiguration; -export let createJWT = OpenIdRecipeWrapper.createJWT; -export let getJWKS = OpenIdRecipeWrapper.getJWKS; diff --git a/lib/ts/recipe/openid/recipe.ts b/lib/ts/recipe/openid/recipe.ts index ad8c93086..07c9af3e1 100644 --- a/lib/ts/recipe/openid/recipe.ts +++ b/lib/ts/recipe/openid/recipe.ts @@ -19,7 +19,6 @@ import RecipeModule from "../../recipeModule"; import { APIHandled, HTTPMethod, NormalisedAppinfo, RecipeListFunction, UserContext } from "../../types"; import { APIInterface, APIOptions, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; import { validateAndNormaliseUserInput } from "./utils"; -import JWTRecipe from "../jwt/recipe"; import OverrideableBuilder from "supertokens-js-override"; import RecipeImplementation from "./recipeImplementation"; import APIImplementation from "./api/implementation"; @@ -32,22 +31,15 @@ export default class OpenIdRecipe extends RecipeModule { static RECIPE_ID = "openid"; private static instance: OpenIdRecipe | undefined = undefined; config: TypeNormalisedInput; - jwtRecipe: JWTRecipe; recipeImplementation: RecipeInterface; apiImpl: APIInterface; - constructor(recipeId: string, appInfo: NormalisedAppinfo, isInServerlessEnv: boolean, config?: TypeInput) { + constructor(recipeId: string, appInfo: NormalisedAppinfo, config?: TypeInput) { super(recipeId, appInfo); - this.config = validateAndNormaliseUserInput(appInfo, config); - this.jwtRecipe = new JWTRecipe(recipeId, appInfo, isInServerlessEnv, { - jwtValiditySeconds: this.config.jwtValiditySeconds, - override: this.config.override.jwtFeature, - }); + this.config = validateAndNormaliseUserInput(config); - let builder = new OverrideableBuilder( - RecipeImplementation(this.config, this.jwtRecipe.recipeInterfaceImpl, appInfo) - ); + let builder = new OverrideableBuilder(RecipeImplementation(appInfo)); this.recipeImplementation = builder.override(this.config.override.functions).build(); @@ -64,9 +56,9 @@ export default class OpenIdRecipe extends RecipeModule { } static init(config?: TypeInput): RecipeListFunction { - return (appInfo, isInServerlessEnv) => { + return (appInfo) => { if (OpenIdRecipe.instance === undefined) { - OpenIdRecipe.instance = new OpenIdRecipe(OpenIdRecipe.RECIPE_ID, appInfo, isInServerlessEnv, config); + OpenIdRecipe.instance = new OpenIdRecipe(OpenIdRecipe.RECIPE_ID, appInfo, config); return OpenIdRecipe.instance; } else { throw new Error("OpenId recipe has already been initialised. Please check your code for bugs."); @@ -81,6 +73,12 @@ export default class OpenIdRecipe extends RecipeModule { OpenIdRecipe.instance = undefined; } + static async getIssuer(userContext: UserContext) { + return ( + await this.getInstanceOrThrowError().recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext }) + ).issuer; + } + getAPIsHandled = (): APIHandled[] => { return [ { @@ -89,16 +87,15 @@ export default class OpenIdRecipe extends RecipeModule { id: GET_DISCOVERY_CONFIG_URL, disabled: this.apiImpl.getOpenIdDiscoveryConfigurationGET === undefined, }, - ...this.jwtRecipe.getAPIsHandled(), ]; }; handleAPIRequest = async ( id: string, - tenantId: string, + _tenantId: string, req: BaseRequest, response: BaseResponse, - path: normalisedURLPath, - method: HTTPMethod, + _path: normalisedURLPath, + _method: HTTPMethod, userContext: UserContext ): Promise => { let apiOptions: APIOptions = { @@ -112,28 +109,16 @@ export default class OpenIdRecipe extends RecipeModule { if (id === GET_DISCOVERY_CONFIG_URL) { return await getOpenIdDiscoveryConfiguration(this.apiImpl, apiOptions, userContext); } else { - return this.jwtRecipe.handleAPIRequest(id, tenantId, req, response, path, method, userContext); + return false; } }; - handleError = async ( - error: STError, - request: BaseRequest, - response: BaseResponse, - userContext: UserContext - ): Promise => { - if (error.fromRecipe === OpenIdRecipe.RECIPE_ID) { - throw error; - } else { - return await this.jwtRecipe.handleError(error, request, response, userContext); - } + handleError = async (error: STError): Promise => { + throw error; }; getAllCORSHeaders = (): string[] => { - return [...this.jwtRecipe.getAllCORSHeaders()]; + return []; }; isErrorFromThisRecipe = (err: any): err is STError => { - return ( - (STError.isErrorFromSuperTokens(err) && err.fromRecipe === OpenIdRecipe.RECIPE_ID) || - this.jwtRecipe.isErrorFromThisRecipe(err) - ); + return STError.isErrorFromSuperTokens(err) && err.fromRecipe === OpenIdRecipe.RECIPE_ID; }; } diff --git a/lib/ts/recipe/openid/recipeImplementation.ts b/lib/ts/recipe/openid/recipeImplementation.ts index 04e992059..5fa6751a3 100644 --- a/lib/ts/recipe/openid/recipeImplementation.ts +++ b/lib/ts/recipe/openid/recipeImplementation.ts @@ -12,8 +12,8 @@ * License for the specific language governing permissions and limitations * under the License. */ -import { RecipeInterface, TypeNormalisedInput } from "./types"; -import { RecipeInterface as JWTRecipeInterface, JsonWebKey } from "../jwt/types"; +import { RecipeInterface } from "./types"; +import JWTRecipe from "../jwt/recipe"; import NormalisedURLPath from "../../normalisedURLPath"; import { GET_JWKS_API } from "../jwt/constants"; import { NormalisedAppinfo, UserContext } from "../../types"; @@ -26,17 +26,13 @@ import { USER_INFO_PATH, } from "../oauth2provider/constants"; -export default function getRecipeInterface( - config: TypeNormalisedInput, - jwtRecipeImplementation: JWTRecipeInterface, - appInfo: NormalisedAppinfo -): RecipeInterface { +export default function getRecipeInterface(appInfo: NormalisedAppinfo): RecipeInterface { return { getOpenIdDiscoveryConfiguration: async function () { - let issuer = config.issuerDomain.getAsStringDangerous() + config.issuerPath.getAsStringDangerous(); + let issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); let jwks_uri = - config.issuerDomain.getAsStringDangerous() + - config.issuerPath.appendPath(new NormalisedURLPath(GET_JWKS_API)).getAsStringDangerous(); + appInfo.apiDomain.getAsStringDangerous() + + appInfo.apiBasePath.appendPath(new NormalisedURLPath(GET_JWKS_API)).getAsStringDangerous(); const apiBasePath = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); return { @@ -54,17 +50,20 @@ export default function getRecipeInterface( response_types_supported: ["code", "id_token", "id_token token"], }; }, - createJWT: async function ({ - payload, - validitySeconds, - useStaticSigningKey, - userContext, - }: { - payload?: any; - validitySeconds?: number; - useStaticSigningKey?: boolean; - userContext: UserContext; - }): Promise< + createJWT: async function ( + this: RecipeInterface, + { + payload, + validitySeconds, + useStaticSigningKey, + userContext, + }: { + payload?: any; + validitySeconds?: number; + useStaticSigningKey?: boolean; + userContext: UserContext; + } + ): Promise< | { status: "OK"; jwt: string; @@ -75,8 +74,8 @@ export default function getRecipeInterface( > { payload = payload === undefined || payload === null ? {} : payload; - let issuer = config.issuerDomain.getAsStringDangerous() + config.issuerPath.getAsStringDangerous(); - return await jwtRecipeImplementation.createJWT({ + let issuer = (await this.getOpenIdDiscoveryConfiguration({ userContext })).issuer; + return await JWTRecipe.getInstanceOrThrowError().recipeInterfaceImpl.createJWT({ payload: { iss: issuer, ...payload, @@ -86,8 +85,5 @@ export default function getRecipeInterface( userContext, }); }, - getJWKS: async function (input): Promise<{ keys: JsonWebKey[] }> { - return await jwtRecipeImplementation.getJWKS(input); - }, }; } diff --git a/lib/ts/recipe/openid/types.ts b/lib/ts/recipe/openid/types.ts index ccd8435ab..11babcb13 100644 --- a/lib/ts/recipe/openid/types.ts +++ b/lib/ts/recipe/openid/types.ts @@ -14,53 +14,25 @@ */ import OverrideableBuilder from "supertokens-js-override"; import type { BaseRequest, BaseResponse } from "../../framework"; -import NormalisedURLDomain from "../../normalisedURLDomain"; -import NormalisedURLPath from "../../normalisedURLPath"; -import { RecipeInterface as JWTRecipeInterface, APIInterface as JWTAPIInterface, JsonWebKey } from "../jwt/types"; import { GeneralErrorResponse, UserContext } from "../../types"; export type TypeInput = { - issuer?: string; - jwtValiditySeconds?: number; override?: { functions?: ( originalImplementation: RecipeInterface, builder?: OverrideableBuilder ) => RecipeInterface; apis?: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; }; }; export type TypeNormalisedInput = { - issuerDomain: NormalisedURLDomain; - issuerPath: NormalisedURLPath; - jwtValiditySeconds?: number; override: { functions: ( originalImplementation: RecipeInterface, builder?: OverrideableBuilder ) => RecipeInterface; apis: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; }; }; @@ -128,10 +100,4 @@ export type RecipeInterface = { status: "UNSUPPORTED_ALGORITHM_ERROR"; } >; - - getJWKS(input: { - userContext: UserContext; - }): Promise<{ - keys: JsonWebKey[]; - }>; }; diff --git a/lib/ts/recipe/openid/utils.ts b/lib/ts/recipe/openid/utils.ts index 72414d9c9..0950214e3 100644 --- a/lib/ts/recipe/openid/utils.ts +++ b/lib/ts/recipe/openid/utils.ts @@ -12,26 +12,9 @@ * License for the specific language governing permissions and limitations * under the License. */ -import NormalisedURLDomain from "../../normalisedURLDomain"; -import NormalisedURLPath from "../../normalisedURLPath"; -import { NormalisedAppinfo } from "../../types"; import { APIInterface, RecipeInterface, TypeInput, TypeNormalisedInput } from "./types"; -export function validateAndNormaliseUserInput(appInfo: NormalisedAppinfo, config?: TypeInput): TypeNormalisedInput { - let issuerDomain = appInfo.apiDomain; - let issuerPath = appInfo.apiBasePath; - - if (config !== undefined) { - if (config.issuer !== undefined) { - issuerDomain = new NormalisedURLDomain(config.issuer); - issuerPath = new NormalisedURLPath(config.issuer); - } - - if (!issuerPath.equals(appInfo.apiBasePath)) { - throw new Error("The path of the issuer URL must be equal to the apiBasePath. The default value is /auth"); - } - } - +export function validateAndNormaliseUserInput(config?: TypeInput): TypeNormalisedInput { let override = { functions: (originalImplementation: RecipeInterface) => originalImplementation, apis: (originalImplementation: APIInterface) => originalImplementation, @@ -39,9 +22,6 @@ export function validateAndNormaliseUserInput(appInfo: NormalisedAppinfo, config }; return { - issuerDomain, - issuerPath, - jwtValiditySeconds: config?.jwtValiditySeconds, override, }; } diff --git a/lib/ts/recipe/session/index.ts b/lib/ts/recipe/session/index.ts index 0df3d7fe0..683ff99a8 100644 --- a/lib/ts/recipe/session/index.ts +++ b/lib/ts/recipe/session/index.ts @@ -26,6 +26,8 @@ import { RecipeInterface, } from "./types"; import Recipe from "./recipe"; +import OpenIdRecipe from "../openid/recipe"; +import JWTRecipe from "../jwt/recipe"; import { JSONObject, UserContext } from "../../types"; import { getRequiredClaimValidators } from "./utils"; import { createNewSessionInRequest, getSessionFromRequest, refreshSessionInRequest } from "./sessionRequestFunctions"; @@ -85,8 +87,7 @@ export default class SessionWrapper { const ctx = getUserContext(userContext); const recipeInstance = Recipe.getInstanceOrThrowError(); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const appInfo = recipeInstance.getAppInfo(); - const issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); + const issuer = await OpenIdRecipe.getIssuer(ctx); let finalAccessTokenPayload = { ...accessTokenPayload, @@ -398,7 +399,7 @@ export default class SessionWrapper { useStaticSigningKey?: boolean, userContext?: Record ) { - return Recipe.getInstanceOrThrowError().openIdRecipe.recipeImplementation.createJWT({ + return OpenIdRecipe.getInstanceOrThrowError().recipeImplementation.createJWT({ payload, validitySeconds, useStaticSigningKey, @@ -407,13 +408,13 @@ export default class SessionWrapper { } static getJWKS(userContext?: Record) { - return Recipe.getInstanceOrThrowError().openIdRecipe.recipeImplementation.getJWKS({ + return JWTRecipe.getInstanceOrThrowError().recipeInterfaceImpl.getJWKS({ userContext: getUserContext(userContext), }); } static getOpenIdDiscoveryConfiguration(userContext?: Record) { - return Recipe.getInstanceOrThrowError().openIdRecipe.recipeImplementation.getOpenIdDiscoveryConfiguration({ + return OpenIdRecipe.getInstanceOrThrowError().recipeImplementation.getOpenIdDiscoveryConfiguration({ userContext: getUserContext(userContext), }); } diff --git a/lib/ts/recipe/session/recipe.ts b/lib/ts/recipe/session/recipe.ts index f077ca776..7dd003e3a 100644 --- a/lib/ts/recipe/session/recipe.ts +++ b/lib/ts/recipe/session/recipe.ts @@ -40,7 +40,6 @@ import APIImplementation from "./api/implementation"; import type { BaseRequest, BaseResponse } from "../../framework"; import OverrideableBuilder from "supertokens-js-override"; import { APIOptions } from "."; -import OpenIdRecipe from "../openid/recipe"; import { logDebugMessage } from "../../logger"; import { resetCombinedJWKS } from "../../combinedRemoteJWKSet"; import { hasGreaterThanEqualToFDI, isTestEnv } from "../../utils"; @@ -56,7 +55,6 @@ export default class SessionRecipe extends RecipeModule { config: TypeNormalisedInput; recipeInterfaceImpl: RecipeInterface; - openIdRecipe: OpenIdRecipe; apiImpl: APIInterface; @@ -82,10 +80,6 @@ export default class SessionRecipe extends RecipeModule { this.isInServerlessEnv = isInServerlessEnv; - this.openIdRecipe = new OpenIdRecipe(recipeId, appInfo, isInServerlessEnv, { - override: this.config.override.openIdFeature, - }); - let builder = new OverrideableBuilder( RecipeImplementation( Querier.getNewInstanceOrThrowError(recipeId), @@ -170,18 +164,16 @@ export default class SessionRecipe extends RecipeModule { }, ]; - apisHandled.push(...this.openIdRecipe.getAPIsHandled()); - return apisHandled; }; handleAPIRequest = async ( id: string, - tenantId: string, + _tenantId: string, req: BaseRequest, res: BaseResponse, - path: NormalisedURLPath, - method: HTTPMethod, + _path: NormalisedURLPath, + _method: HTTPMethod, userContext: UserContext ): Promise => { let options: APIOptions = { @@ -197,7 +189,7 @@ export default class SessionRecipe extends RecipeModule { } else if (id === SIGNOUT_API_PATH) { return await signOutAPI(this.apiImpl, options, userContext); } else { - return await this.openIdRecipe.handleAPIRequest(id, tenantId, req, res, path, method, userContext); + return false; } }; @@ -247,23 +239,18 @@ export default class SessionRecipe extends RecipeModule { throw err; } } else { - return await this.openIdRecipe.handleError(err, request, response, userContext); + throw err; } }; getAllCORSHeaders = (): string[] => { let corsHeaders: string[] = [...getCORSAllowedHeadersFromCookiesAndHeaders()]; - corsHeaders.push(...this.openIdRecipe.getAllCORSHeaders()); - return corsHeaders; }; isErrorFromThisRecipe = (err: any): err is STError => { - return ( - STError.isErrorFromSuperTokens(err) && - (err.fromRecipe === SessionRecipe.RECIPE_ID || this.openIdRecipe.isErrorFromThisRecipe(err)) - ); + return STError.isErrorFromSuperTokens(err) && err.fromRecipe === SessionRecipe.RECIPE_ID; }; verifySession = async ( diff --git a/lib/ts/recipe/session/sessionRequestFunctions.ts b/lib/ts/recipe/session/sessionRequestFunctions.ts index c6cb64158..cde8c6744 100644 --- a/lib/ts/recipe/session/sessionRequestFunctions.ts +++ b/lib/ts/recipe/session/sessionRequestFunctions.ts @@ -8,6 +8,7 @@ import { } from "./types"; import frameworks from "../../framework"; import SuperTokens from "../../supertokens"; +import OpenIdRecipe from "../openid/recipe"; import { getRequiredClaimValidators } from "./utils"; import { getRidFromHeader, isAnIpAddress, normaliseHttpMethod, setRequestInUserContextIfNotDefined } from "../../utils"; import { logDebugMessage } from "../../logger"; @@ -444,7 +445,7 @@ export async function createNewSessionInRequest({ userContext = setRequestInUserContextIfNotDefined(userContext, req); const claimsAddedByOtherRecipes = recipeInstance.getClaimsAddedByOtherRecipes(); - const issuer = appInfo.apiDomain.getAsStringDangerous() + appInfo.apiBasePath.getAsStringDangerous(); + const issuer = await OpenIdRecipe.getIssuer(userContext); let finalAccessTokenPayload = { ...accessTokenPayload, diff --git a/lib/ts/recipe/session/types.ts b/lib/ts/recipe/session/types.ts index d714981d0..accd318bc 100644 --- a/lib/ts/recipe/session/types.ts +++ b/lib/ts/recipe/session/types.ts @@ -14,9 +14,7 @@ */ import type { BaseRequest, BaseResponse } from "../../framework"; import NormalisedURLPath from "../../normalisedURLPath"; -import { RecipeInterface as JWTRecipeInterface, APIInterface as JWTAPIInterface } from "../jwt/types"; import OverrideableBuilder from "supertokens-js-override"; -import { RecipeInterface as OpenIdRecipeInterface, APIInterface as OpenIdAPIInterface } from "../openid/types"; import { JSONObject, JSONValue, UserContext } from "../../types"; import { GeneralErrorResponse } from "../../types"; import RecipeUserId from "../../recipeUserId"; @@ -88,26 +86,6 @@ export type TypeInput = { builder?: OverrideableBuilder ) => RecipeInterface; apis?: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - openIdFeature?: { - functions?: ( - originalImplementation: OpenIdRecipeInterface, - builder?: OverrideableBuilder - ) => OpenIdRecipeInterface; - apis?: ( - originalImplementation: OpenIdAPIInterface, - builder?: OverrideableBuilder - ) => OpenIdAPIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; - }; }; }; @@ -147,26 +125,6 @@ export type TypeNormalisedInput = { builder?: OverrideableBuilder ) => RecipeInterface; apis: (originalImplementation: APIInterface, builder?: OverrideableBuilder) => APIInterface; - openIdFeature?: { - functions?: ( - originalImplementation: OpenIdRecipeInterface, - builder?: OverrideableBuilder - ) => OpenIdRecipeInterface; - apis?: ( - originalImplementation: OpenIdAPIInterface, - builder?: OverrideableBuilder - ) => OpenIdAPIInterface; - jwtFeature?: { - functions?: ( - originalImplementation: JWTRecipeInterface, - builder?: OverrideableBuilder - ) => JWTRecipeInterface; - apis?: ( - originalImplementation: JWTAPIInterface, - builder?: OverrideableBuilder - ) => JWTAPIInterface; - }; - }; }; }; diff --git a/lib/ts/supertokens.ts b/lib/ts/supertokens.ts index f330266de..145266186 100644 --- a/lib/ts/supertokens.ts +++ b/lib/ts/supertokens.ts @@ -105,6 +105,8 @@ export default class SuperTokens { let userMetadataFound = false; let multiFactorAuthFound = false; let oauth2Found = false; + let openIdFound = false; + let jwtFound = false; // Multitenancy recipe is an always initialized recipe and needs to be imported this way // so that there is no circular dependency. Otherwise there would be cyclic dependency @@ -114,6 +116,8 @@ export default class SuperTokens { let MultiFactorAuthRecipe = require("./recipe/multifactorauth/recipe").default; let TotpRecipe = require("./recipe/totp/recipe").default; let OAuth2ProviderRecipe = require("./recipe/oauth2provider/recipe").default; + let OpenIdRecipe = require("./recipe/openid/recipe").default; + let jwtRecipe = require("./recipe/jwt/recipe").default; this.recipeModules = config.recipeList.map((func) => { const recipeModule = func(this.appInfo, this.isInServerlessEnv); @@ -127,10 +131,20 @@ export default class SuperTokens { totpFound = true; } else if (recipeModule.getRecipeId() === OAuth2ProviderRecipe.RECIPE_ID) { oauth2Found = true; + } else if (recipeModule.getRecipeId() === OpenIdRecipe.RECIPE_ID) { + openIdFound = true; + } else if (recipeModule.getRecipeId() === jwtRecipe.RECIPE_ID) { + jwtFound = true; } return recipeModule; }); + if (!jwtFound) { + this.recipeModules.push(jwtRecipe.init()(this.appInfo, this.isInServerlessEnv)); + } + if (!openIdFound) { + this.recipeModules.push(OpenIdRecipe.init()(this.appInfo, this.isInServerlessEnv)); + } if (!multitenancyFound) { this.recipeModules.push(MultitenancyRecipe.init()(this.appInfo, this.isInServerlessEnv)); } @@ -166,11 +180,15 @@ export default class SuperTokens { throw new Error("calling testing function in non testing env"); } - // We call reset the OAuth2Provider recipe because it is auto-initialized + // We call reset the following recipes because they are auto-initialized // and there is no case where we want to reset the SuperTokens instance but not // the recipes. let OAuth2ProviderRecipe = require("./recipe/oauth2provider/recipe").default; OAuth2ProviderRecipe.reset(); + let OpenIdRecipe = require("./recipe/openid/recipe").default; + OpenIdRecipe.reset(); + let JWTRecipe = require("./recipe/jwt/recipe").default; + JWTRecipe.reset(); Querier.reset(); SuperTokens.instance = undefined; diff --git a/recipe/openid/index.d.ts b/recipe/openid/index.d.ts new file mode 100644 index 000000000..64f95c7b5 --- /dev/null +++ b/recipe/openid/index.d.ts @@ -0,0 +1,10 @@ +export * from "../../lib/build/recipe/openid"; +/** + * 'export *' does not re-export a default. + * import NextJS from "supertokens-node/nextjs"; + * the above import statement won't be possible unless either + * - user add "esModuleInterop": true in their tsconfig.json file + * - we do the following change: + */ +import * as _default from "../../lib/build/recipe/openid"; +export default _default; diff --git a/recipe/openid/index.js b/recipe/openid/index.js new file mode 100644 index 000000000..276ef8f9d --- /dev/null +++ b/recipe/openid/index.js @@ -0,0 +1,6 @@ +"use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +exports.__esModule = true; +__export(require("../../lib/build/recipe/openid")); diff --git a/recipe/openid/types/index.d.ts b/recipe/openid/types/index.d.ts new file mode 100644 index 000000000..2c15f75f4 --- /dev/null +++ b/recipe/openid/types/index.d.ts @@ -0,0 +1,10 @@ +export * from "../../../lib/build/recipe/openid/types"; +/** + * 'export *' does not re-export a default. + * import NextJS from "supertokens-node/nextjs"; + * the above import statement won't be possible unless either + * - user add "esModuleInterop": true in their tsconfig.json file + * - we do the following change: + */ +import * as _default from "../../../lib/build/recipe/openid/types"; +export default _default; diff --git a/recipe/openid/types/index.js b/recipe/openid/types/index.js new file mode 100644 index 000000000..26a5b76d2 --- /dev/null +++ b/recipe/openid/types/index.js @@ -0,0 +1,6 @@ +"use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +exports.__esModule = true; +__export(require("../../../lib/build/recipe/openid/types")); diff --git a/test/openid/config.test.js b/test/openid/config.test.js index 2a73550a0..1f7a52438 100644 --- a/test/openid/config.test.js +++ b/test/openid/config.test.js @@ -40,10 +40,7 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () return; } - let openIdRecipe = await OpenIdRecipe.getInstanceOrThrowError(); - - assert(openIdRecipe.config.issuerDomain.getAsStringDangerous() === "https://api.supertokens.io"); - assert(openIdRecipe.config.issuerPath.getAsStringDangerous() === "/auth"); + assert((await OpenIdRecipe.getIssuer()) === "https://api.supertokens.io/auth"); }); it("Test that the default config sets values correctly for OpenID recipe with apiBasePath", async function () { @@ -68,10 +65,7 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () return; } - let openIdRecipe = await OpenIdRecipe.getInstanceOrThrowError(); - - assert(openIdRecipe.config.issuerDomain.getAsStringDangerous() === "https://api.supertokens.io"); - assert(openIdRecipe.config.issuerPath.getAsStringDangerous() === ""); + assert((await OpenIdRecipe.getIssuer()) === "https://api.supertokens.io"); }); it("Test that the config sets values correctly for OpenID recipe with issuer", async function () { @@ -88,7 +82,18 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () }, recipeList: [ OpenIdRecipe.init({ - issuer: "https://customissuer.com", + override: { + functions: (originalImplementation) => ({ + ...originalImplementation, + getOpenIdDiscoveryConfiguration: async (input) => { + const orig = originalImplementation.getOpenIdDiscoveryConfiguration(input); + return { + ...orig, + issuer: "https://customissuer.com", + }; + }, + }), + }, }), ], }); @@ -100,38 +105,7 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () return; } - let openIdRecipe = await OpenIdRecipe.getInstanceOrThrowError(); - - assert(openIdRecipe.config.issuerDomain.getAsStringDangerous() === "https://customissuer.com"); - assert(openIdRecipe.config.issuerPath.getAsStringDangerous() === ""); - }); - - it("Test that issuer without apiBasePath throws error", async function () { - const connectionURI = await startST(); - - try { - STExpress.init({ - supertokens: { - connectionURI, - }, - appInfo: { - apiDomain: "api.supertokens.io", - appName: "SuperTokens", - websiteDomain: "supertokens.io", - }, - recipeList: [ - OpenIdRecipe.init({ - issuer: "https://customissuer.com", - }), - ], - }); - } catch (e) { - if ( - e.message !== "The path of the issuer URL must be equal to the apiBasePath. The default value is /auth" - ) { - throw e; - } - } + assert((await OpenIdRecipe.getIssuer()) === "https://customissuer.com"); }); it("Test that issuer with gateway path works fine", async function () { @@ -156,9 +130,6 @@ describe(`configTest: ${printPath("[test/openid/config.test.js]")}`, function () return; } - let openIdRecipe = await OpenIdRecipe.getInstanceOrThrowError(); - - assert.equal(openIdRecipe.config.issuerDomain.getAsStringDangerous(), "https://api.supertokens.io"); - assert.equal(openIdRecipe.config.issuerPath.getAsStringDangerous(), "/gateway/auth"); + assert.equal(await OpenIdRecipe.getIssuer(), "https://api.supertokens.io/gateway/auth"); }); }); diff --git a/test/openid/openid.test.js b/test/openid/openid.test.js index 657f4958d..909a412f6 100644 --- a/test/openid/openid.test.js +++ b/test/openid/openid.test.js @@ -88,7 +88,19 @@ describe(`openIdTest: ${printPath("[test/openid/openid.test.js]")}`, function () }, recipeList: [ OpenIdRecipe.init({ - issuer: "https://cusomissuer/auth", + override: { + functions: (originalImplementation) => ({ + ...originalImplementation, + getOpenIdDiscoveryConfiguration: async (input) => { + const orig = originalImplementation.getOpenIdDiscoveryConfiguration(input); + return { + ...orig, + issuer: "https://cusomissuer/auth", + jwks_uri: "https://cusomissuer/auth/jwt/jwks.json", + }; + }, + }), + }, }), ], }); diff --git a/test/with-typescript/index.ts b/test/with-typescript/index.ts index 437f15fe0..b9be6ec15 100644 --- a/test/with-typescript/index.ts +++ b/test/with-typescript/index.ts @@ -11,6 +11,7 @@ import NextJS from "../../nextjs"; import ThirdParty from "../../recipe/thirdparty"; import Multitenancy from "../../recipe/multitenancy"; import Passwordless from "../../recipe/passwordless"; +import OpenId from "../../recipe/openid"; import { SMTPService as SMTPServiceTPP } from "../../recipe/passwordless/emaildelivery"; import { SMTPService as SMTPServiceP } from "../../recipe/passwordless/emaildelivery"; import { SMTPService as SMTPServiceTPEP } from "../../recipe/emailpassword/emaildelivery"; @@ -1606,25 +1607,28 @@ Session.init({ }); }, }), - openIdFeature: { - functions: (oI) => ({ - ...oI, - getOpenIdDiscoveryConfiguration: async (input) => ({ - issuer: "your issuer", - jwks_uri: "https://your.api.domain/auth/jwt/jwks.json", - token_endpoint: "http://localhost:3000/auth/oauth2/token", - authorization_endpoint: "http://localhost:3000/auth/oauth2/auth", - userinfo_endpoint: "http://localhost:3000/auth/oauth2/userinfo", - revocation_endpoint: "http://localhost:3000/auth/oauth2/revoke", - token_introspection_endpoint: "http://localhost:3000/auth/oauth2/introspect", - end_session_endpoint: "http://localhost:3000/auth/oauth2/introspect", - id_token_signing_alg_values_supported: [], - response_types_supported: [], - subject_types_supported: [], - status: "OK", - }), + }, +}); + +OpenId.init({ + override: { + functions: (oI) => ({ + ...oI, + getOpenIdDiscoveryConfiguration: async (input) => ({ + issuer: "your issuer", + jwks_uri: "https://your.api.domain/auth/jwt/jwks.json", + token_endpoint: "http://localhost:3000/auth/oauth2/token", + authorization_endpoint: "http://localhost:3000/auth/oauth2/auth", + userinfo_endpoint: "http://localhost:3000/auth/oauth2/userinfo", + revocation_endpoint: "http://localhost:3000/auth/oauth2/revoke", + token_introspection_endpoint: "http://localhost:3000/auth/oauth2/introspect", + end_session_endpoint: "http://localhost:3000/auth/oauth2/introspect", + id_token_signing_alg_values_supported: [], + response_types_supported: [], + subject_types_supported: [], + status: "OK", }), - }, + }), }, }); @@ -1886,21 +1890,17 @@ Passwordless.init({ const recipeUserId = new Supertokens.RecipeUserId("asdf"); -Session.init({ +JWT.init({ override: { - openIdFeature: { - jwtFeature: { - apis: (oI) => { - return { - ...oI, - getJWKSGET: async function (input) { - let result = await oI.getJWKSGET!(input); - input.options.res.setHeader("custom-header", "custom-value", false); - return result; - }, - }; + apis: (oI) => { + return { + ...oI, + getJWKSGET: async function (input) { + let result = await oI.getJWKSGET!(input); + input.options.res.setHeader("custom-header", "custom-value", false); + return result; }, - }, + }; }, }, });