diff --git a/internal/api/oidc/auth_request_integration_test.go b/internal/api/oidc/auth_request_integration_test.go index e2e6ae2f7b..630b20bc09 100644 --- a/internal/api/oidc/auth_request_integration_test.go +++ b/internal/api/oidc/auth_request_integration_test.go @@ -528,6 +528,9 @@ func assertTokens(t *testing.T, tokens *oidc.Tokens[*oidc.IDTokenClaims], requir } else { assert.Empty(t, tokens.RefreshToken) } + // since we test implicit flow directly, we can check that any token response must not + // return a `state` in the response + assert.Empty(t, tokens.Extra("state")) } func assertIDTokenClaims(t *testing.T, claims *oidc.IDTokenClaims, userID string, arm []string, sessionStart, sessionChange time.Time, sessionID string) { diff --git a/internal/api/oidc/token_code.go b/internal/api/oidc/token_code.go index b7ccd1d22f..2e47c55641 100644 --- a/internal/api/oidc/token_code.go +++ b/internal/api/oidc/token_code.go @@ -34,41 +34,40 @@ func (s *Server) CodeExchange(ctx context.Context, r *op.ClientRequest[oidc.Acce var ( session *command.OIDCSession - state string ) if strings.HasPrefix(plainCode, command.IDPrefixV2) { - session, state, err = s.command.CreateOIDCSessionFromAuthRequest( + session, _, err = s.command.CreateOIDCSessionFromAuthRequest( setContextUserSystem(ctx), plainCode, codeExchangeComplianceChecker(client, r.Data), slices.Contains(client.GrantTypes(), oidc.GrantTypeRefreshToken), ) } else { - session, state, err = s.codeExchangeV1(ctx, client, r.Data, r.Data.Code) + session, err = s.codeExchangeV1(ctx, client, r.Data, r.Data.Code) } if err != nil { return nil, err } - return response(s.accessTokenResponseFromSession(ctx, client, session, state, client.client.ProjectID, client.client.ProjectRoleAssertion, client.client.AccessTokenRoleAssertion, client.client.IDTokenRoleAssertion, client.client.IDTokenUserinfoAssertion)) + return response(s.accessTokenResponseFromSession(ctx, client, session, "", client.client.ProjectID, client.client.ProjectRoleAssertion, client.client.AccessTokenRoleAssertion, client.client.IDTokenRoleAssertion, client.client.IDTokenUserinfoAssertion)) } // codeExchangeV1 creates a v2 token from a v1 auth request. -func (s *Server) codeExchangeV1(ctx context.Context, client *Client, req *oidc.AccessTokenRequest, code string) (session *command.OIDCSession, state string, err error) { +func (s *Server) codeExchangeV1(ctx context.Context, client *Client, req *oidc.AccessTokenRequest, code string) (session *command.OIDCSession, err error) { ctx, span := tracing.NewSpan(ctx) defer func() { span.EndWithError(err) }() authReq, err := s.getAuthRequestV1ByCode(ctx, code) if err != nil { - return nil, "", err + return nil, err } if challenge := authReq.GetCodeChallenge(); challenge != nil || client.AuthMethod() == oidc.AuthMethodNone { if err = op.AuthorizeCodeChallenge(req.CodeVerifier, challenge); err != nil { - return nil, "", err + return nil, err } } if req.RedirectURI != authReq.GetRedirectURI() { - return nil, "", oidc.ErrInvalidGrant().WithDescription("redirect_uri does not correspond") + return nil, oidc.ErrInvalidGrant().WithDescription("redirect_uri does not correspond") } scope := authReq.GetScopes() @@ -88,9 +87,9 @@ func (s *Server) codeExchangeV1(ctx context.Context, client *Client, req *oidc.A slices.Contains(scope, oidc.ScopeOfflineAccess), ) if err != nil { - return nil, "", err + return nil, err } - return session, authReq.TransferState, s.repo.DeleteAuthRequest(ctx, authReq.ID) + return session, s.repo.DeleteAuthRequest(ctx, authReq.ID) } // getAuthRequestV1ByCode finds the v1 auth request by code.