feat: add support for OAuth 2.0 Authorization Server Issuer Identification

This commit is contained in:
Elias Schneider
2025-07-06 15:29:26 +02:00
parent 49f1ab2f75
commit bf042563e9
5 changed files with 22 additions and 17 deletions

View File

@@ -89,6 +89,7 @@ func (oc *OidcController) authorizeHandler(c *gin.Context) {
response := dto.AuthorizeOidcClientResponseDto{ response := dto.AuthorizeOidcClientResponseDto{
Code: code, Code: code,
CallbackURL: callbackURL, CallbackURL: callbackURL,
Issuer: common.EnvConfig.AppURL,
} }
c.JSON(http.StatusOK, response) c.JSON(http.StatusOK, response)

View File

@@ -69,20 +69,21 @@ func (wkc *WellKnownController) computeOIDCConfiguration() ([]byte, error) {
return nil, fmt.Errorf("failed to get key algorithm: %w", err) return nil, fmt.Errorf("failed to get key algorithm: %w", err)
} }
config := map[string]any{ config := map[string]any{
"issuer": appUrl, "issuer": appUrl,
"authorization_endpoint": appUrl + "/authorize", "authorization_endpoint": appUrl + "/authorize",
"token_endpoint": appUrl + "/api/oidc/token", "token_endpoint": appUrl + "/api/oidc/token",
"userinfo_endpoint": appUrl + "/api/oidc/userinfo", "userinfo_endpoint": appUrl + "/api/oidc/userinfo",
"end_session_endpoint": appUrl + "/api/oidc/end-session", "end_session_endpoint": appUrl + "/api/oidc/end-session",
"introspection_endpoint": appUrl + "/api/oidc/introspect", "introspection_endpoint": appUrl + "/api/oidc/introspect",
"device_authorization_endpoint": appUrl + "/api/oidc/device/authorize", "device_authorization_endpoint": appUrl + "/api/oidc/device/authorize",
"jwks_uri": appUrl + "/.well-known/jwks.json", "jwks_uri": appUrl + "/.well-known/jwks.json",
"grant_types_supported": []string{service.GrantTypeAuthorizationCode, service.GrantTypeRefreshToken, service.GrantTypeDeviceCode}, "grant_types_supported": []string{service.GrantTypeAuthorizationCode, service.GrantTypeRefreshToken, service.GrantTypeDeviceCode},
"scopes_supported": []string{"openid", "profile", "email", "groups"}, "scopes_supported": []string{"openid", "profile", "email", "groups"},
"claims_supported": []string{"sub", "given_name", "family_name", "name", "email", "email_verified", "preferred_username", "picture", "groups"}, "claims_supported": []string{"sub", "given_name", "family_name", "name", "email", "email_verified", "preferred_username", "picture", "groups"},
"response_types_supported": []string{"code", "id_token"}, "response_types_supported": []string{"code", "id_token"},
"subject_types_supported": []string{"public"}, "subject_types_supported": []string{"public"},
"id_token_signing_alg_values_supported": []string{alg.String()}, "id_token_signing_alg_values_supported": []string{alg.String()},
"authorization_response_iss_parameter_supported": true,
} }
return json.Marshal(config) return json.Marshal(config)
} }

View File

@@ -57,6 +57,7 @@ type AuthorizeOidcClientRequestDto struct {
type AuthorizeOidcClientResponseDto struct { type AuthorizeOidcClientResponseDto struct {
Code string `json:"code"` Code string `json:"code"`
CallbackURL string `json:"callbackURL"` CallbackURL string `json:"callbackURL"`
Issuer string `json:"issuer"`
} }
type AuthorizationRequiredDto struct { type AuthorizationRequiredDto struct {

View File

@@ -48,4 +48,5 @@ export type OidcDeviceCodeInfo = {
export type AuthorizeResponse = { export type AuthorizeResponse = {
code: string; code: string;
callbackURL: string; callbackURL: string;
issuer: string;
}; };

View File

@@ -57,8 +57,8 @@
await oidService await oidService
.authorize(client!.id, scope, callbackURL, nonce, codeChallenge, codeChallengeMethod) .authorize(client!.id, scope, callbackURL, nonce, codeChallenge, codeChallengeMethod)
.then(async ({ code, callbackURL }) => { .then(async ({ code, callbackURL, issuer }) => {
onSuccess(code, callbackURL); onSuccess(code, callbackURL, issuer);
}); });
} catch (e) { } catch (e) {
errorMessage = getWebauthnErrorMessage(e); errorMessage = getWebauthnErrorMessage(e);
@@ -66,12 +66,13 @@
} }
} }
function onSuccess(code: string, callbackURL: string) { function onSuccess(code: string, callbackURL: string, issuer: string) {
success = true; success = true;
setTimeout(() => { setTimeout(() => {
const redirectURL = new URL(callbackURL); const redirectURL = new URL(callbackURL);
redirectURL.searchParams.append('code', code); redirectURL.searchParams.append('code', code);
redirectURL.searchParams.append('state', authorizeState); redirectURL.searchParams.append('state', authorizeState);
redirectURL.searchParams.append('iss', issuer);
window.location.href = redirectURL.toString(); window.location.href = redirectURL.toString();
}, 1000); }, 1000);