Merge commit from fork

* fix: client_id verification during code exchange and refresh token flows

* add clientID check for device token flow

* Trigger Build
This commit is contained in:
Gayathri Vijayan
2026-06-16 15:19:56 +02:00
committed by GitHub
parent e94d4c3986
commit 0973b074b4
8 changed files with 257 additions and 9 deletions
@@ -117,6 +117,62 @@ func TestOPStorage_CreateAccessToken_code(t *testing.T) {
}
}
func TestOPStorage_CreateAccessToken_code_invalid_client(t *testing.T) {
tests := []struct {
name string
authorizeClientID string
codeExchangeClientID string
authRequestID func(t testing.TB, instance *integration.Instance, clientID, redirectURI string, scope ...string) string
}{
{
name: "login header",
authorizeClientID: func() string {
clientID, _ := createClient(t, Instance)
return clientID
}(),
codeExchangeClientID: func() string {
clientID, _ := createClient(t, Instance)
return clientID
}(),
authRequestID: createAuthRequest,
},
{
name: "login v2 config",
authorizeClientID: func() string {
clientID, _ := createClientLoginV2(t, Instance)
return clientID
}(),
codeExchangeClientID: func() string {
clientID, _ := createClientLoginV2(t, Instance)
return clientID
}(),
authRequestID: createAuthRequestNoLoginClientHeader,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
authRequestID := createAuthRequest(t, Instance, tt.authorizeClientID, redirectURI)
sessionID, sessionToken, _, _ := Instance.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
linkResp, err := Instance.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
AuthRequestId: authRequestID,
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
Session: &oidc_pb.Session{
SessionId: sessionID,
SessionToken: sessionToken,
},
},
})
require.NoError(t, err)
code := assertCodeResponse(t, linkResp.GetCallbackUrl())
// the client used for code exchange does not match the client in the auth request -> must fail
tokens, err := exchangeTokens(t, Instance, tt.codeExchangeClientID, code, redirectURI)
require.ErrorContains(t, err, "client_id does not correspond to the client_id in the authorization request")
assert.Nil(t, tokens)
})
}
}
func TestOPStorage_CreateAccessToken_implicit(t *testing.T) {
tests := []struct {
name string
@@ -295,6 +351,68 @@ func TestOPStorage_CreateAccessAndRefreshTokens_refresh(t *testing.T) {
}
}
func TestOPStorage_CreateAccessAndRefreshTokens_refresh_invalid_client(t *testing.T) {
tests := []struct {
name string
clientID string
otherClientID string
authRequestID func(t testing.TB, instance *integration.Instance, clientID, redirectURI string, scope ...string) string
}{
{
name: "login header",
clientID: func() string {
clientID, _ := createClient(t, Instance)
return clientID
}(),
otherClientID: func() string {
clientID, _ := createClient(t, Instance)
return clientID
}(),
authRequestID: createAuthRequest,
},
{
name: "login v2 config",
clientID: func() string {
clientID, _ := createClientLoginV2(t, Instance)
return clientID
}(),
otherClientID: func() string {
clientID, _ := createClient(t, Instance)
return clientID
}(),
authRequestID: createAuthRequestNoLoginClientHeader,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
authRequestID := tt.authRequestID(t, Instance, tt.clientID, redirectURI, oidc.ScopeOpenID, oidc.ScopeOfflineAccess)
sessionID, sessionToken, startTime, changeTime := Instance.CreateVerifiedWebAuthNSession(t, CTXLOGIN, User.GetUserId())
linkResp, err := Instance.Client.OIDCv2.CreateCallback(CTXLOGIN, &oidc_pb.CreateCallbackRequest{
AuthRequestId: authRequestID,
CallbackKind: &oidc_pb.CreateCallbackRequest_Session{
Session: &oidc_pb.Session{
SessionId: sessionID,
SessionToken: sessionToken,
},
},
})
require.NoError(t, err)
// code exchange
code := assertCodeResponse(t, linkResp.GetCallbackUrl())
tokens, err := exchangeTokens(t, Instance, tt.clientID, code, redirectURI)
require.NoError(t, err)
assertTokens(t, tokens, true)
assertIDTokenClaims(t, tokens.IDTokenClaims, User.GetUserId(), armPasskey, startTime, changeTime, sessionID)
// refresh grant with a different client -> must fail
newTokens, err := refreshTokens(t, tt.otherClientID, tokens.RefreshToken)
require.ErrorContains(t, err, "client_id does not correspond to the client_id in the refresh token")
assert.Nil(t, newTokens)
})
}
}
func TestOPStorage_RevokeToken_access_token(t *testing.T) {
clientID, _ := createClient(t, Instance)
provider, err := Instance.CreateRelyingParty(CTX, clientID, redirectURI)