mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-12 00:27:31 +00:00
feat(oidc): optimize the userinfo endpoint (#7706)
* feat(oidc): optimize the userinfo endpoint
* store project ID in the access token
* query for projectID if not in token
* add scope based tests
* Revert "store project ID in the access token"
This reverts commit 5f0262f239
.
* query project role assertion
* use project role assertion setting to return roles
* workaround eventual consistency and handle PAT
* do not append empty project id
This commit is contained in:
@@ -28,7 +28,6 @@ func (s *Server) Introspect(ctx context.Context, r *op.Request[op.IntrospectionR
|
||||
return s.LegacyServer.Introspect(ctx, r)
|
||||
}
|
||||
if features.TriggerIntrospectionProjections {
|
||||
// Execute all triggers in one concurrent sweep.
|
||||
query.TriggerIntrospectionProjections(ctx)
|
||||
}
|
||||
|
||||
@@ -100,7 +99,7 @@ func (s *Server) Introspect(ctx context.Context, r *op.Request[op.IntrospectionR
|
||||
if err = validateIntrospectionAudience(token.audience, client.clientID, client.projectID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userInfo, err := s.userInfo(ctx, token.userID, client.projectID, token.scope, []string{client.projectID})
|
||||
userInfo, err := s.userInfo(ctx, token.userID, client.projectID, client.projectRoleAssertion, token.scope, []string{client.projectID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -124,9 +123,10 @@ func (s *Server) Introspect(ctx context.Context, r *op.Request[op.IntrospectionR
|
||||
}
|
||||
|
||||
type introspectionClientResult struct {
|
||||
clientID string
|
||||
projectID string
|
||||
err error
|
||||
clientID string
|
||||
projectID string
|
||||
projectRoleAssertion bool
|
||||
err error
|
||||
}
|
||||
|
||||
var errNoClientSecret = errors.New("client has no configured secret")
|
||||
@@ -134,35 +134,36 @@ var errNoClientSecret = errors.New("client has no configured secret")
|
||||
func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCredentials, rc chan<- *introspectionClientResult) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
|
||||
clientID, projectID, err := func() (string, string, error) {
|
||||
clientID, projectID, projectRoleAssertion, err := func() (string, string, bool, error) {
|
||||
client, err := s.clientFromCredentials(ctx, cc)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", "", false, err
|
||||
}
|
||||
|
||||
if cc.ClientAssertion != "" {
|
||||
verifier := op.NewJWTProfileVerifierKeySet(keySetMap(client.PublicKeys), op.IssuerFromContext(ctx), time.Hour, time.Second)
|
||||
if _, err := op.VerifyJWTAssertion(ctx, cc.ClientAssertion, verifier); err != nil {
|
||||
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
||||
return "", "", false, oidc.ErrUnauthorizedClient().WithParent(err)
|
||||
}
|
||||
return client.ClientID, client.ProjectID, nil
|
||||
return client.ClientID, client.ProjectID, client.ProjectRoleAssertion, nil
|
||||
|
||||
}
|
||||
if client.HashedSecret != "" {
|
||||
if err := s.introspectionClientSecretAuth(ctx, client, cc.ClientSecret); err != nil {
|
||||
return "", "", oidc.ErrUnauthorizedClient().WithParent(err)
|
||||
return "", "", false, oidc.ErrUnauthorizedClient().WithParent(err)
|
||||
}
|
||||
return client.ClientID, client.ProjectID, nil
|
||||
return client.ClientID, client.ProjectID, client.ProjectRoleAssertion, nil
|
||||
}
|
||||
return "", "", oidc.ErrUnauthorizedClient().WithParent(errNoClientSecret)
|
||||
return "", "", false, oidc.ErrUnauthorizedClient().WithParent(errNoClientSecret)
|
||||
}()
|
||||
|
||||
span.EndWithError(err)
|
||||
|
||||
rc <- &introspectionClientResult{
|
||||
clientID: clientID,
|
||||
projectID: projectID,
|
||||
err: err,
|
||||
clientID: clientID,
|
||||
projectID: projectID,
|
||||
projectRoleAssertion: projectRoleAssertion,
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user