Cut user-owned API keys; redesign subject model
Removes the APIKey primitive entirely (Auth.IssueAPIKey/AuthenticateAPIKey/
RevokeAPIKey, APIKeyStore, Deps.APIKeys, Stores.APIKeys, Tables.APIKeys,
ErrAPIKeyInvalid, AuthMethodAPIKey, Principal.{APIKeyID, Abilities, HasAbility},
prefixAPIKey, RequireAPIKey, and the 6 SQL templates). Migration
0003_drop_api_keys.sql hard-drops authkit_api_keys.
The new subject model: *Principal carries identity only (sessions, JWTs);
*ServiceKey is the only abilities-bearing credential and gains a
HasAbility(name) method. RequireAbility now reads *ServiceKey from context
(user principals 403 by design). RequireRole/RequirePermission stay
Principal-only. New RequireServiceKey + ServiceKeyFrom + MustServiceKey,
and a heterogeneous RequireAnyOrServiceKey for routes that accept either.
RequireAny is now Principal-only (default [Session, JWT]).
Adds 7 middleware tests (auth, revoked, ability accept/reject across
subjects, role rejects service key, RequireAnyOrServiceKey both paths) and
1 (*ServiceKey).HasAbility unit test. Existing API-key tests deleted.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4942e4dbdc
commit
7f1db871bc
24 changed files with 773 additions and 496 deletions
31
models.go
31
models.go
|
|
@ -49,21 +49,12 @@ type Token struct {
|
|||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
type APIKey struct {
|
||||
IDHash []byte
|
||||
OwnerID uuid.UUID
|
||||
Name string
|
||||
Abilities []string
|
||||
LastUsedAt *time.Time
|
||||
CreatedAt time.Time
|
||||
ExpiresAt *time.Time
|
||||
RevokedAt *time.Time
|
||||
}
|
||||
|
||||
// ServiceKey is an owner-agnostic API key for server-to-server auth. Unlike
|
||||
// APIKey, OwnerID is not constrained to authkit_users — OwnerKind labels the
|
||||
// owner namespace (e.g. "application", "tenant") and consumers manage their
|
||||
// own cascade-on-delete.
|
||||
// ServiceKey is an owner-agnostic credential for server-to-server auth.
|
||||
// OwnerID is not constrained to authkit_users — OwnerKind labels the owner
|
||||
// namespace (e.g. "application", "tenant") and consumers manage their own
|
||||
// cascade-on-delete. It is the only credential type that carries free-form
|
||||
// abilities; user-bound credentials (sessions, JWTs) prove identity and
|
||||
// resolve permissions through RBAC instead.
|
||||
type ServiceKey struct {
|
||||
IDHash []byte
|
||||
OwnerID uuid.UUID
|
||||
|
|
@ -76,6 +67,16 @@ type ServiceKey struct {
|
|||
RevokedAt *time.Time
|
||||
}
|
||||
|
||||
// HasAbility reports whether the service key carries the named ability.
|
||||
func (k *ServiceKey) HasAbility(name string) bool {
|
||||
for _, a := range k.Abilities {
|
||||
if a == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Role struct {
|
||||
ID uuid.UUID
|
||||
Name string
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue