mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:07:31 +00:00
perf(oidc): remove get user by ID from jwt profile grant (#8580)
# Which Problems Are Solved Improve performance by removing a GetUserByID call. The call also executed a Trigger on projections, which significantly impacted concurrent requests. # How the Problems Are Solved Token creation needs information from the user, such as the resource owner and access token type. For client credentials this is solved in a single search. By getting the user by username (`client_id`), the user details and secret were obtained in a single query. After that verification and token creation can proceed. For JWT profile it is a bit more complex. We didn't know anything about the user until after JWT verification. The verification did a query for the AuthN key and after that we did a GetUserByID to get remaining details. This change uses a joined query when the OIDC library calls the `GetKeyByIDAndClientID` method on the token storage. The found user details are set to the verifieer object and returned after verification is completed. It is safe because the `jwtProfileKeyStorage` is a single-use object as a wrapper around `query.Queries`. This way getting the public key and user details are obtained in a single query. # Additional Changes - Correctly set the `client_id` field with machine's username. # Additional Context - Related to: https://github.com/zitadel/zitadel/issues/8352
This commit is contained in:
@@ -3,6 +3,7 @@ package query
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
@@ -249,6 +250,44 @@ func NewAuthNKeyObjectIDQuery(id string) (SearchQuery, error) {
|
||||
return NewTextQuery(AuthNKeyColumnObjectID, id, TextEquals)
|
||||
}
|
||||
|
||||
//go:embed authn_key_user.sql
|
||||
var authNKeyUserQuery string
|
||||
|
||||
type AuthNKeyUser struct {
|
||||
UserID string
|
||||
ResourceOwner string
|
||||
Username string
|
||||
TokenType domain.OIDCTokenType
|
||||
PublicKey []byte
|
||||
}
|
||||
|
||||
func (q *Queries) GetAuthNKeyUser(ctx context.Context, keyID, userID string) (_ *AuthNKeyUser, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
dst := new(AuthNKeyUser)
|
||||
err = q.client.QueryRowContext(ctx, func(row *sql.Row) error {
|
||||
return row.Scan(
|
||||
&dst.UserID,
|
||||
&dst.ResourceOwner,
|
||||
&dst.Username,
|
||||
&dst.TokenType,
|
||||
&dst.PublicKey,
|
||||
)
|
||||
},
|
||||
authNKeyUserQuery,
|
||||
authz.GetInstance(ctx).InstanceID(),
|
||||
keyID, userID,
|
||||
)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, zerrors.ThrowNotFound(err, "QUERY-Tha6f", "Errors.AuthNKey.NotFound")
|
||||
}
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-aen2A", "Errors.Internal")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func prepareAuthNKeysQuery(ctx context.Context, db prepareDatabase) (sq.SelectBuilder, func(rows *sql.Rows) (*AuthNKeys, error)) {
|
||||
return sq.Select(
|
||||
AuthNKeyColumnID.identifier(),
|
||||
|
Reference in New Issue
Block a user