From bf042563e997d57bb087705a5789fd72ffbed467 Mon Sep 17 00:00:00 2001 From: Elias Schneider Date: Sun, 6 Jul 2025 15:29:26 +0200 Subject: [PATCH] feat: add support for OAuth 2.0 Authorization Server Issuer Identification --- .../internal/controller/oidc_controller.go | 1 + .../controller/well_known_controller.go | 29 ++++++++++--------- backend/internal/dto/oidc_dto.go | 1 + frontend/src/lib/types/oidc.type.ts | 1 + frontend/src/routes/authorize/+page.svelte | 7 +++-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/backend/internal/controller/oidc_controller.go b/backend/internal/controller/oidc_controller.go index 13adaf49..3ffba2ce 100644 --- a/backend/internal/controller/oidc_controller.go +++ b/backend/internal/controller/oidc_controller.go @@ -89,6 +89,7 @@ func (oc *OidcController) authorizeHandler(c *gin.Context) { response := dto.AuthorizeOidcClientResponseDto{ Code: code, CallbackURL: callbackURL, + Issuer: common.EnvConfig.AppURL, } c.JSON(http.StatusOK, response) diff --git a/backend/internal/controller/well_known_controller.go b/backend/internal/controller/well_known_controller.go index 6c45a8b4..e8f01746 100644 --- a/backend/internal/controller/well_known_controller.go +++ b/backend/internal/controller/well_known_controller.go @@ -69,20 +69,21 @@ func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) { return nil, fmt.Errorf("failed to get key algorithm: %w", err) } config := map[string]any{ - "issuer": appUrl, - "authorization_endpoint": appUrl + "/authorize", - "token_endpoint": appUrl + "/api/oidc/token", - "userinfo_endpoint": appUrl + "/api/oidc/userinfo", - "end_session_endpoint": appUrl + "/api/oidc/end-session", - "introspection_endpoint": appUrl + "/api/oidc/introspect", - "device_authorization_endpoint": appUrl + "/api/oidc/device/authorize", - "jwks_uri": appUrl + "/.well-known/jwks.json", - "grant_types_supported": []string{service.GrantTypeAuthorizationCode, service.GrantTypeRefreshToken, service.GrantTypeDeviceCode}, - "scopes_supported": []string{"openid", "profile", "email", "groups"}, - "claims_supported": []string{"sub", "given_name", "family_name", "name", "email", "email_verified", "preferred_username", "picture", "groups"}, - "response_types_supported": []string{"code", "id_token"}, - "subject_types_supported": []string{"public"}, - "id_token_signing_alg_values_supported": []string{alg.String()}, + "issuer": appUrl, + "authorization_endpoint": appUrl + "/authorize", + "token_endpoint": appUrl + "/api/oidc/token", + "userinfo_endpoint": appUrl + "/api/oidc/userinfo", + "end_session_endpoint": appUrl + "/api/oidc/end-session", + "introspection_endpoint": appUrl + "/api/oidc/introspect", + "device_authorization_endpoint": appUrl + "/api/oidc/device/authorize", + "jwks_uri": appUrl + "/.well-known/jwks.json", + "grant_types_supported": []string{service.GrantTypeAuthorizationCode, service.GrantTypeRefreshToken, service.GrantTypeDeviceCode}, + "scopes_supported": []string{"openid", "profile", "email", "groups"}, + "claims_supported": []string{"sub", "given_name", "family_name", "name", "email", "email_verified", "preferred_username", "picture", "groups"}, + "response_types_supported": []string{"code", "id_token"}, + "subject_types_supported": []string{"public"}, + "id_token_signing_alg_values_supported": []string{alg.String()}, + "authorization_response_iss_parameter_supported": true, } return json.Marshal(config) } diff --git a/backend/internal/dto/oidc_dto.go b/backend/internal/dto/oidc_dto.go index 22f8a805..86f0a643 100644 --- a/backend/internal/dto/oidc_dto.go +++ b/backend/internal/dto/oidc_dto.go @@ -57,6 +57,7 @@ type AuthorizeOidcClientRequestDto struct { type AuthorizeOidcClientResponseDto struct { Code string `json:"code"` CallbackURL string `json:"callbackURL"` + Issuer string `json:"issuer"` } type AuthorizationRequiredDto struct { diff --git a/frontend/src/lib/types/oidc.type.ts b/frontend/src/lib/types/oidc.type.ts index 0a1a18c2..9aeaa554 100644 --- a/frontend/src/lib/types/oidc.type.ts +++ b/frontend/src/lib/types/oidc.type.ts @@ -48,4 +48,5 @@ export type OidcDeviceCodeInfo = { export type AuthorizeResponse = { code: string; callbackURL: string; + issuer: string; }; diff --git a/frontend/src/routes/authorize/+page.svelte b/frontend/src/routes/authorize/+page.svelte index 66ae7ee0..6c60d62b 100644 --- a/frontend/src/routes/authorize/+page.svelte +++ b/frontend/src/routes/authorize/+page.svelte @@ -57,8 +57,8 @@ await oidService .authorize(client!.id, scope, callbackURL, nonce, codeChallenge, codeChallengeMethod) - .then(async ({ code, callbackURL }) => { - onSuccess(code, callbackURL); + .then(async ({ code, callbackURL, issuer }) => { + onSuccess(code, callbackURL, issuer); }); } catch (e) { errorMessage = getWebauthnErrorMessage(e); @@ -66,12 +66,13 @@ } } - function onSuccess(code: string, callbackURL: string) { + function onSuccess(code: string, callbackURL: string, issuer: string) { success = true; setTimeout(() => { const redirectURL = new URL(callbackURL); redirectURL.searchParams.append('code', code); redirectURL.searchParams.append('state', authorizeState); + redirectURL.searchParams.append('iss', issuer); window.location.href = redirectURL.toString(); }, 1000);