diff --git a/.changeset/early-feet-lay.md b/.changeset/early-feet-lay.md index d6f62d1129..ee6fd89730 100644 --- a/.changeset/early-feet-lay.md +++ b/.changeset/early-feet-lay.md @@ -3,3 +3,15 @@ --- Added custom timeout setting for oidc provider + +Here is an example of how to use a custom timeout with the configuration: + +```yaml +auth: + oidc: + production: + clientId: ${AUTH_GOOGLE_CLIENT_ID} + clientSecret: ${AUTH_GOOGLE_CLIENT_SECRET} + timeout: + seconds: 30 +``` diff --git a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts index 38e134bcd0..d12427f127 100644 --- a/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts +++ b/plugins/auth-backend-module-oidc-provider/src/authenticator.test.ts @@ -28,6 +28,7 @@ import { ConfigReader } from '@backstage/config'; import { JWK, SignJWT, exportJWK, generateKeyPair } from 'jose'; import { rest } from 'msw'; import express from 'express'; +import { custom } from 'openid-client'; describe('oidcAuthenticator', () => { let implementation: any; @@ -169,6 +170,81 @@ describe('oidcAuthenticator', () => { jest.clearAllMocks(); }); + describe('timeout configuration', () => { + const TEST_URL = new URL('https://test.com'); + + it('should use default timeout when no timeout is configured', async () => { + const { promise } = oidcAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + metadataUrl: 'https://oidc.test/.well-known/openid-configuration', + clientId: 'clientId', + clientSecret: 'clientSecret', + }), + }); + const { client } = await promise; + + const timeout = client[custom.http_options](TEST_URL, {}).timeout; + + // Check if the HTTP timeout is set to the default value + expect(timeout).toBeDefined(); + expect(timeout).toBe(10000); + }); + + it('should use configured timeout when provided in the config', async () => { + const { promise } = oidcAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + metadataUrl: 'https://oidc.test/.well-known/openid-configuration', + clientId: 'clientId', + clientSecret: 'clientSecret', + timeout: { + seconds: 30, + }, + }), + }); + const { client } = await promise; + + const timeout = client[custom.http_options](TEST_URL, {}).timeout; + + // Check if the HTTP timeout is set to the configured value (30 seconds) + expect(timeout).toBeDefined(); + expect(timeout).toBe(30000); + }); + + it('should handle invalid timeout configuration gracefully', async () => { + expect(() => { + oidcAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + metadataUrl: 'https://oidc.test/.well-known/openid-configuration', + clientId: 'clientId', + clientSecret: 'clientSecret', + timeout: '30s', + }), + }); + }).toThrow( + "Failed to read duration from config, TypeError: Invalid type in config for key 'timeout' in 'mock-config', got string, wanted object", + ); + + expect(() => { + oidcAuthenticator.initialize({ + callbackUrl: 'https://backstage.test/callback', + config: new ConfigReader({ + metadataUrl: 'https://oidc.test/.well-known/openid-configuration', + clientId: 'clientId', + clientSecret: 'clientSecret', + timeout: { + seconds: '30s', + }, + }), + }); + }).toThrow( + "Failed to read duration from config, Error: Unable to convert config value for key 'timeout.seconds' in 'mock-config' to a number", + ); + }); + }); + describe('#start', () => { let fakeSession: Record; let startRequest: OAuthAuthenticatorStartInput;