From 6539d9a15ca38cfeb49da656b7a953f9eda20445 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Fri, 23 Jan 2026 10:46:51 +0000 Subject: [PATCH 1/4] feat: Add organization option to auth0 auth provider Signed-off-by: Jack Palmer --- .../config.d.ts | 1 + .../package.json | 2 + .../src/authenticator.ts | 2 + .../src/strategy.ts | 16 +++ .../src/types.d.ts | 100 ++++++++++++++++++ yarn.lock | 2 + 6 files changed, 123 insertions(+) create mode 100644 plugins/auth-backend-module-auth0-provider/src/types.d.ts diff --git a/plugins/auth-backend-module-auth0-provider/config.d.ts b/plugins/auth-backend-module-auth0-provider/config.d.ts index 661409a592..d2b1c66389 100644 --- a/plugins/auth-backend-module-auth0-provider/config.d.ts +++ b/plugins/auth-backend-module-auth0-provider/config.d.ts @@ -32,6 +32,7 @@ export interface Config { audience?: string; connection?: string; connectionScope?: string; + organization?: string; sessionDuration?: HumanDuration | string; }; }; diff --git a/plugins/auth-backend-module-auth0-provider/package.json b/plugins/auth-backend-module-auth0-provider/package.json index 8b749bc420..7ca877a6a2 100644 --- a/plugins/auth-backend-module-auth0-provider/package.json +++ b/plugins/auth-backend-module-auth0-provider/package.json @@ -37,6 +37,7 @@ "@backstage/backend-plugin-api": "workspace:^", "@backstage/plugin-auth-node": "workspace:^", "express": "^4.22.0", + "passport": "^0.7.0", "passport-auth0": "^1.4.3", "passport-oauth2": "^1.6.1" }, @@ -46,6 +47,7 @@ "@backstage/cli": "workspace:^", "@backstage/plugin-auth-backend": "workspace:^", "@backstage/types": "workspace:^", + "@types/passport": "^1.0.3", "@types/passport-auth0": "^1.0.5", "@types/passport-oauth2": "^1.4.15", "supertest": "^7.0.0" diff --git a/plugins/auth-backend-module-auth0-provider/src/authenticator.ts b/plugins/auth-backend-module-auth0-provider/src/authenticator.ts index a042f113f8..5ed5fc580c 100644 --- a/plugins/auth-backend-module-auth0-provider/src/authenticator.ts +++ b/plugins/auth-backend-module-auth0-provider/src/authenticator.ts @@ -35,6 +35,7 @@ export const auth0Authenticator = createOAuthAuthenticator({ const connection = config.getOptionalString('connection'); const connectionScope = config.getOptionalString('connectionScope'); const callbackURL = config.getOptionalString('callbackUrl') ?? callbackUrl; + const organization = config.getOptionalString('organization'); // Due to passport-auth0 forcing options.state = true, // passport-oauth2 requires express-session to be installed // so that the 'state' parameter of the oauth2 flow can be stored. @@ -58,6 +59,7 @@ export const auth0Authenticator = createOAuthAuthenticator({ callbackURL, domain, store, + organization, // We need passReqToCallback set to false to get params, but there's // no matching type signature for that, so instead behold this beauty passReqToCallback: false as true, diff --git a/plugins/auth-backend-module-auth0-provider/src/strategy.ts b/plugins/auth-backend-module-auth0-provider/src/strategy.ts index 039885dddb..a8699555a7 100644 --- a/plugins/auth-backend-module-auth0-provider/src/strategy.ts +++ b/plugins/auth-backend-module-auth0-provider/src/strategy.ts @@ -25,10 +25,13 @@ export interface Auth0StrategyOptionsWithRequest { domain: string; passReqToCallback: true; store: StateStore; + organization?: string; } /** @public */ export class Auth0Strategy extends Auth0InternalStrategy { + private organization: string | undefined; + constructor( options: Auth0StrategyOptionsWithRequest, verify: Auth0InternalStrategy.VerifyFunction, @@ -41,5 +44,18 @@ export class Auth0Strategy extends Auth0InternalStrategy { apiUrl: `https://${options.domain}/api`, }; super(optionsWithURLs, verify); + this.organization = options.organization; + } + + authorizationParams(options: Record): Record { + const params = super.authorizationParams(options); + + if (this.organization) { + return { + ...params, + organization: this.organization, + }; + } + return params; } } diff --git a/plugins/auth-backend-module-auth0-provider/src/types.d.ts b/plugins/auth-backend-module-auth0-provider/src/types.d.ts new file mode 100644 index 0000000000..f0efc49347 --- /dev/null +++ b/plugins/auth-backend-module-auth0-provider/src/types.d.ts @@ -0,0 +1,100 @@ +/* + * Copyright 2026 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ + +declare module 'passport-auth0' { + import passport from 'passport'; + import express from 'express'; + + declare class StrategyInternal extends passport.Strategy { + constructor( + options: StrategyInternal.StrategyOptionWithRequest, + verify: StrategyInternal.VerifyFunctionWithRequest, + ); + constructor( + options: StrategyInternal.StrategyOption, + verify: StrategyInternal.VerifyFunction, + ); + + name: string; + authenticate(req: express.Request, options?: object): void; + authorizationParams(options: Record): Record; + } + + declare namespace StrategyInternal { + interface Profile extends passport.Profile { + id: string; + displayName: string; + gender?: string | undefined; + ageRange?: + | { + min: number; + max?: number | undefined; + } + | undefined; + profileUrl?: string | undefined; + username?: string | undefined; + birthday: string; + + _raw: string; + _json: any; + } + + interface AuthenticateOptions extends passport.AuthenticateOptions { + authType?: string | undefined; + } + + interface StrategyOption { + clientID: string; + clientSecret: string; + callbackURL: string; + domain: string; + scopeSeparator?: string | undefined; + enableProof?: boolean | undefined; + profileFields?: string[] | undefined; + state?: boolean | undefined; + } + + interface StrategyOptionWithRequest extends StrategyOption { + passReqToCallback: true; + } + interface ExtraVerificationParams { + audience?: string | undefined; + connection?: string | undefined; + prompt?: string | undefined; + } + + type VerifyFunction = ( + accessToken: string, + refreshToken: string, + extraParams: ExtraVerificationParams, + profile: Profile, + done: (error: any, user?: any, info?: any) => void, + ) => void; + + type VerifyFunctionWithRequest = ( + req: express.Request, + accessToken: string, + refreshToken: string, + extraParams: ExtraVerificationParams, + profile: Profile, + done: (error: any, user?: any, info?: any) => void, + ) => void; + + export import Strategy = StrategyInternal; + } + + export = StrategyInternal; +} diff --git a/yarn.lock b/yarn.lock index 675eba1c8c..8a2dfb2568 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4283,9 +4283,11 @@ __metadata: "@backstage/plugin-auth-backend": "workspace:^" "@backstage/plugin-auth-node": "workspace:^" "@backstage/types": "workspace:^" + "@types/passport": "npm:^1.0.3" "@types/passport-auth0": "npm:^1.0.5" "@types/passport-oauth2": "npm:^1.4.15" express: "npm:^4.22.0" + passport: "npm:^0.7.0" passport-auth0: "npm:^1.4.3" passport-oauth2: "npm:^1.6.1" supertest: "npm:^7.0.0" From 36804fed6ef3b6e25bcdfcfcfa80d32a7d5ac4f6 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Fri, 23 Jan 2026 10:48:38 +0000 Subject: [PATCH 2/4] chore: add changeset Signed-off-by: Jack Palmer --- .changeset/chatty-tips-stop.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/chatty-tips-stop.md diff --git a/.changeset/chatty-tips-stop.md b/.changeset/chatty-tips-stop.md new file mode 100644 index 0000000000..7b4c435ffc --- /dev/null +++ b/.changeset/chatty-tips-stop.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-auth-backend-module-auth0-provider': minor +--- + +feat: Added organization option to authorization params of the strategy From 59c06a215edaf6cf627753462f522b7d8a2ee4ca Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Fri, 23 Jan 2026 10:53:35 +0000 Subject: [PATCH 3/4] chore: update documentation Signed-off-by: Jack Palmer --- docs/auth/auth0/provider.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/auth/auth0/provider.md b/docs/auth/auth0/provider.md index 90ac36f07d..b836bf01f6 100644 --- a/docs/auth/auth0/provider.md +++ b/docs/auth/auth0/provider.md @@ -44,6 +44,7 @@ auth: audience: ${AUTH_AUTH0_AUDIENCE} connection: ${AUTH_AUTH0_CONNECTION} connectionScope: ${AUTH_AUTH0_CONNECTION_SCOPE} + organization: ${AUTH_AUTH0_ORGANIZATION_ID} ## uncomment to set lifespan of user session # sessionDuration: { hours: 24 } # supports `ms` library format (e.g. '24h', '2 days'), ISO duration, "human duration" as used in code session: @@ -69,6 +70,7 @@ Auth0 requires a session, so you need to give the session a secret key. - `connection`: Social identity provider name. To check the available social connections, please visit [Auth0 Social Connections](https://marketplace.auth0.com/features/social-connections). - `connectionScope`: Additional scopes in the interactive token request. It should always be used in combination with the `connection` parameter. - `sessionDuration`: Lifespan of the user session. +- `organization`: Specify a specific organization ID to be targeted as part of the login flow. ### Resolvers From 29ddd3cf43929aafda99eec612157f1fd1aa90b7 Mon Sep 17 00:00:00 2001 From: Jack Palmer Date: Fri, 23 Jan 2026 11:33:26 +0000 Subject: [PATCH 4/4] chore: fix types Signed-off-by: Jack Palmer --- plugins/auth-backend-module-auth0-provider/src/types.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/auth-backend-module-auth0-provider/src/types.d.ts b/plugins/auth-backend-module-auth0-provider/src/types.d.ts index f0efc49347..8d4d182728 100644 --- a/plugins/auth-backend-module-auth0-provider/src/types.d.ts +++ b/plugins/auth-backend-module-auth0-provider/src/types.d.ts @@ -18,7 +18,7 @@ declare module 'passport-auth0' { import passport from 'passport'; import express from 'express'; - declare class StrategyInternal extends passport.Strategy { + class StrategyInternal extends passport.Strategy { constructor( options: StrategyInternal.StrategyOptionWithRequest, verify: StrategyInternal.VerifyFunctionWithRequest, @@ -33,7 +33,7 @@ declare module 'passport-auth0' { authorizationParams(options: Record): Record; } - declare namespace StrategyInternal { + namespace StrategyInternal { interface Profile extends passport.Profile { id: string; displayName: string;