package auth import ( "context" "errors" ) var ( // ErrInvalidAPIKey is returned when the API key is invalid. ErrInvalidAPIKey = errors.New("invalid API key") ) // APIKeyLookup is a function that looks up a user by API key. // Returns nil user and no error if the key is not found. type APIKeyLookup func(ctx context.Context, key string) (*User, error) // APIKeyValidator validates API keys using a lookup function. type APIKeyValidator struct { lookup APIKeyLookup } // NewAPIKeyValidator creates a new API key validator. // // Example with database lookup: // // validator := auth.NewAPIKeyValidator(func(ctx context.Context, key string) (*auth.User, error) { // apiKey, err := db.GetAPIKeyByHash(ctx, hashKey(key)) // if err != nil { // return nil, err // } // if apiKey == nil { // return nil, nil // Key not found // } // return &auth.User{ // ID: apiKey.UserID, // Scopes: apiKey.Scopes, // }, nil // }) func NewAPIKeyValidator(lookup APIKeyLookup) *APIKeyValidator { return &APIKeyValidator{lookup: lookup} } // Validate validates an API key and returns the associated user. func (v *APIKeyValidator) Validate(ctx context.Context, key string) (*User, error) { if key == "" { return nil, ErrInvalidAPIKey } user, err := v.lookup(ctx, key) if err != nil { return nil, err } if user == nil { return nil, ErrInvalidAPIKey } return user, nil } // StaticAPIKeyValidator validates against a static set of API keys. // Useful for simple use cases or testing. type StaticAPIKeyValidator struct { keys map[string]*User } // NewStaticAPIKeyValidator creates a validator with static API keys. // // Example: // // validator := auth.NewStaticAPIKeyValidator(map[string]*auth.User{ // "sk-test-123": {ID: "user-1", Scopes: []string{"read", "write"}}, // "sk-test-456": {ID: "user-2", Scopes: []string{"read"}}, // }) func NewStaticAPIKeyValidator(keys map[string]*User) *StaticAPIKeyValidator { return &StaticAPIKeyValidator{keys: keys} } // Validate validates an API key against the static key map. func (v *StaticAPIKeyValidator) Validate(ctx context.Context, key string) (*User, error) { if key == "" { return nil, ErrInvalidAPIKey } user, ok := v.keys[key] if !ok { return nil, ErrInvalidAPIKey } return user, nil }