diff --git a/plugins/auth-backend/api-report.md b/plugins/auth-backend/api-report.md index 18924f7c23..41342bf03d 100644 --- a/plugins/auth-backend/api-report.md +++ b/plugins/auth-backend/api-report.md @@ -12,6 +12,7 @@ import { Config } from '@backstage/config'; import { Entity } from '@backstage/catalog-model'; import express from 'express'; import { GetEntitiesRequest } from '@backstage/catalog-client'; +import { IncomingHttpHeaders } from 'http'; import { JsonValue } from '@backstage/types'; import { Logger } from 'winston'; import { PluginDatabaseManager } from '@backstage/backend-common'; @@ -566,6 +567,7 @@ export type Oauth2ProxyProviderOptions = { export type OAuth2ProxyResult = { fullProfile: JWTPayload; accessToken: string; + headers: IncomingHttpHeaders; }; // Warning: (ae-missing-release-tag) "OAuthAdapter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts index acef4a74ef..0cd600bfce 100644 --- a/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts +++ b/plugins/auth-backend/src/providers/oauth2-proxy/provider.ts @@ -27,6 +27,7 @@ import { import { decodeJwt } from 'jose'; import { prepareBackstageIdentityResponse } from '../prepareBackstageIdentityResponse'; import { createAuthProviderIntegration } from '../createAuthProviderIntegration'; +import { IncomingHttpHeaders } from 'http'; export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; @@ -39,13 +40,30 @@ export const OAUTH2_PROXY_JWT_HEADER = 'X-OAUTH2-PROXY-ID-TOKEN'; export type OAuth2ProxyResult = { /** * Parsed and decoded JWT payload. + * + * @deprecated Access through the `headers` instead. This will be removed in a future release. */ fullProfile: JWTPayload; /** * Raw JWT token + * + * @deprecated Access through the `headers` instead. This will be removed in a future release. */ accessToken: string; + + /** + * The headers of the incoming request from the OAuth2 proxy. This will include + * both the headers set by the client as well as the ones added by the OAuth2 proxy. + * You should only trust the headers that are injected by the OAuth2 proxy. + * + * Useful headers to use to complete the sign-in are for example `x-forwarded-user` + * and `x-forwarded-email`. See the OAuth2 proxy documentation for more information + * about the available headers and how to enable them. In particular it is possible + * to forward access and identity tokens, which can be user for additional verification + * and lookups. + */ + headers: IncomingHttpHeaders; }; /** @@ -96,7 +114,17 @@ export class Oauth2ProxyAuthProvider async refresh(req: express.Request, res: express.Response): Promise { try { - const result = this.getResult(req); + // TODO(Rugvip): This parsing was deprecated in 1.2 and should be removed in a future release. + const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER); + const jwt = getBearerTokenFromAuthorizationHeader(authHeader); + const decodedJWT = jwt && (decodeJwt(jwt) as unknown as JWTPayload); + + const result = { + fullProfile: decodedJWT || ({} as JWTPayload), + accessToken: jwt || '', + headers: req.headers, + }; + const response = await this.handleResult(result); res.json(response); } catch (e) { @@ -131,24 +159,6 @@ export class Oauth2ProxyAuthProvider profile, }; } - - private getResult(req: express.Request): OAuth2ProxyResult { - const authHeader = req.header(OAUTH2_PROXY_JWT_HEADER); - const jwt = getBearerTokenFromAuthorizationHeader(authHeader); - - if (!jwt) { - throw new AuthenticationError( - `Missing or in incorrect format - Oauth2Proxy OIDC header: ${OAUTH2_PROXY_JWT_HEADER}`, - ); - } - - const decodedJWT = decodeJwt(jwt) as unknown as JWTPayload; - - return { - fullProfile: decodedJWT, - accessToken: jwt, - }; - } } /**