chore: Throw error when organization declared in strategy does not match organization in request

Signed-off-by: Jack Palmer <jackpalmer@spotify.com>
This commit is contained in:
Jack Palmer
2026-02-05 15:20:32 +00:00
parent 3458f3a731
commit bf3861fdb6
4 changed files with 108 additions and 5 deletions
@@ -35,6 +35,7 @@
},
"dependencies": {
"@backstage/backend-plugin-api": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/plugin-auth-node": "workspace:^",
"express": "^4.22.0",
"passport": "^0.7.0",
@@ -54,9 +54,7 @@ describe('authModuleAuth0Provider', () => {
const agent = request.agent(server);
const res = await agent.get(
'/api/auth/auth0/start?env=development&organization=foo-organization&invitation=foo-invitation',
);
const res = await agent.get('/api/auth/auth0/start?env=development');
expect(res.status).toEqual(302);
@@ -80,8 +78,6 @@ describe('authModuleAuth0Provider', () => {
accessType: 'offline',
connection: 'connection',
connection_scope: 'connectionScope',
organization: 'foo-organization',
invitation: 'foo-invitation',
nonce: expect.any(String),
state: expect.any(String),
});
@@ -91,4 +87,97 @@ describe('authModuleAuth0Provider', () => {
nonce: decodeURIComponent(nonceCookie.value),
});
});
it('should pass through organization and invitation parameters to the authorization URL', async () => {
const { server } = await startTestBackend({
features: [
authPlugin,
authModuleAuth0Provider,
mockServices.rootConfig.factory({
data: {
app: {
baseUrl: 'http://localhost:3000',
},
auth: {
providers: {
auth0: {
development: {
clientId: 'clientId',
clientSecret: 'clientSecret',
domain: 'domain',
connection: 'connection',
connectionScope: 'connectionScope',
organization: 'foo-organization',
},
},
},
session: {
secret: 'secret',
},
},
},
}),
],
});
const agent = request.agent(server);
const res = await agent.get(
'/api/auth/auth0/start?env=development&organization=foo-organization&invitation=foo-invitation',
);
const startUrl = new URL(res.get('location'));
expect(startUrl.origin).toBe('https://domain');
expect(startUrl.pathname).toBe('/authorize');
expect(Object.fromEntries(startUrl.searchParams)).toEqual(
expect.objectContaining({
organization: 'foo-organization',
invitation: 'foo-invitation',
}),
);
});
it('should throw an error if the organization in the request does not match the organization configured in the strategy', async () => {
const { server } = await startTestBackend({
features: [
authPlugin,
authModuleAuth0Provider,
mockServices.rootConfig.factory({
data: {
app: {
baseUrl: 'http://localhost:3000',
},
auth: {
providers: {
auth0: {
development: {
clientId: 'clientId',
clientSecret: 'clientSecret',
domain: 'domain',
connection: 'connection',
connectionScope: 'connectionScope',
organization: 'bar-organization',
},
},
},
session: {
secret: 'secret',
},
},
},
}),
],
});
const agent = request.agent(server);
const res = await agent.get(
'/api/auth/auth0/start?env=development&organization=foo-organization&invitation=foo-invitation',
);
expect(res.status).toEqual(409);
expect(res.text).toContain(
'Organization mismatch. The organization provided in the request does not match the organization configured in the strategy.',
);
});
});
@@ -17,6 +17,7 @@
import Auth0InternalStrategy from 'passport-auth0';
import type { StateStore } from 'passport-oauth2';
import type express from 'express';
import { ConflictError } from '@backstage/errors';
/** @public */
export interface Auth0StrategyOptionsWithRequest {
@@ -51,6 +52,17 @@ export class Auth0Strategy extends Auth0InternalStrategy {
authenticate(req: express.Request, options: Record<string, any>): void {
const { organization, invitation } = req.query;
// Throw an error if the organization in the request does not match the organization configured in the strategy
if (
organization &&
this.organization &&
organization !== this.organization
) {
throw new ConflictError(
'Organization mismatch. The organization provided in the request does not match the organization configured in the strategy.',
);
}
super.authenticate(req, {
...options,
...(organization ? { organization } : {}),
+1
View File
@@ -4284,6 +4284,7 @@ __metadata:
"@backstage/backend-plugin-api": "workspace:^"
"@backstage/backend-test-utils": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/errors": "workspace:^"
"@backstage/plugin-auth-backend": "workspace:^"
"@backstage/plugin-auth-node": "workspace:^"
"@backstage/types": "workspace:^"