core

package
v0.42.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: MIT Imports: 39 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ErrCodeUsernameTooShort            = "username_too_short"
	ErrCodeUsernameTooLong             = "username_too_long"
	ErrCodeUsernameMustStartWithLetter = "username_must_start_with_letter"
	ErrCodeUsernameCannotContainAt     = "username_cannot_contain_at"
	ErrCodeUsernameCannotStartWithPlus = "username_cannot_start_with_plus"
	ErrCodeUsernameInvalidCharacters   = "username_invalid_characters"
	ErrCodeOwnerSlugTaken              = "owner_slug_taken"
	ErrCodeUsernameNotAllowed          = "username_not_allowed"
	ErrCodeRenameRateLimited           = "rename_rate_limited"
	ErrCodeInvalidEmail                = "invalid_email"
	ErrCodeInvalidPhoneNumber          = "invalid_phone_number"
	ErrCodePasswordTooShort            = "password_too_short"
)
View Source
const (
	// PermWildcard is the wildcard CHARACTER used inside namespace-anchored
	// globs (`org:*`, `org:members:*`, `org:*:read`, `platform:*`). A bare
	// standalone `*` is NOT a valid grant — it is rejected everywhere.
	PermWildcard = "*"

	// authkit base org-management permissions, granular CRUD per resource
	// (#95). They gate authkit's own org-management endpoints. Old coarse
	// `org:<resource>:manage` + `org:read` were RETIRED in favor of these
	// concrete actions plus globs (`org:members:*`, `org:*:read`).
	PermOrgMembersCreate = "org:members:create" // add a member
	PermOrgMembersRead   = "org:members:read"   // list members + their roles
	PermOrgMembersUpdate = "org:members:update" // change a member's roles
	PermOrgMembersDelete = "org:members:delete" // remove a member

	PermOrgRolesCreate = "org:roles:create" // define a role
	PermOrgRolesRead   = "org:roles:read"   // list roles + their perms
	PermOrgRolesUpdate = "org:roles:update" // set perms / rename a role
	PermOrgRolesDelete = "org:roles:delete" // delete a role

	PermOrgAPIKeysCreate = "org:api_keys:create" // mint an API key
	PermOrgAPIKeysRead   = "org:api_keys:read"   // list API-key metadata (NEVER the secret)
	PermOrgAPIKeysDelete = "org:api_keys:delete" // revoke an API key (no update — immutable; rotate = create+delete)

	PermOrgRemoteAppsCreate = "org:remote_applications:create" // register an org-owned remote application
	PermOrgRemoteAppsRead   = "org:remote_applications:read"   // list + detail
	PermOrgRemoteAppsUpdate = "org:remote_applications:update" // edit config / origins / memberships
	PermOrgRemoteAppsDelete = "org:remote_applications:delete" // delete

	PermOrgSettingsRead   = "org:settings:read"   // read the org's own name/profile (GET /orgs/{org})
	PermOrgSettingsUpdate = "org:settings:update" // rename / edit metadata (POST /orgs/{org}/rename)

	// OrgOwnerGrant is the apex grant held by the prebuilt `owner` role: every
	// permission in the `org:` namespace for that ONE org (#95 — tightened from
	// a bare `*`). It covers AuthKit's base resources AND every host-declared
	// `org:<resource>` perm in a single grant, but can NEVER reach the separate
	// `platform:` layer.
	OrgOwnerGrant = "org:*"
)
View Source
const (
	PermPlatformUsersRead   = "platform:users:read"   // read the global account directory
	PermPlatformUsersUpdate = "platform:users:update" // edit an account (email/username/password/sessions)
	PermPlatformUsersBan    = "platform:users:ban"    // ban / unban an account
	PermPlatformUsersDelete = "platform:users:delete" // soft-delete / restore an account

	PermPlatformOrgsRead          = "platform:orgs:read"           // the org directory (list/inspect any org as an entity)
	PermPlatformOrgsUpdate        = "platform:orgs:update"         // rename / transfer-owner of any org
	PermPlatformOrgsDelete        = "platform:orgs:delete"         // soft-delete / restore any org
	PermPlatformOrgsReservedNames = "platform:orgs:reserved-names" // restrict/unrestrict/park/claim the org slug pool
	PermPlatformOrgsRecover       = "platform:orgs:recover"        // anti-takeover reset of a compromised org

	PermPlatformRolesCreate = "platform:roles:create" // define a platform role
	PermPlatformRolesRead   = "platform:roles:read"   // list platform roles + perms
	PermPlatformRolesUpdate = "platform:roles:update" // set perms on / rename a platform role
	PermPlatformRolesDelete = "platform:roles:delete" // delete a platform role

	PermPlatformMembersCreate = "platform:members:create" // grant a user a platform role (mint a platform-admin)
	PermPlatformMembersRead   = "platform:members:read"   // list the platform-admin roster
	PermPlatformMembersDelete = "platform:members:delete" // revoke a user's platform role

	PermPlatformMetricsRead = "platform:metrics:read" // read platform metrics

	// PlatformSuperAdminGrant is the apex platform grant (super-admin): every
	// permission in the `platform:` namespace. It can NEVER reach the separate
	// `org:` layer (disjoint) — a super-admin manages entities, never an org's
	// internals.
	PlatformSuperAdminGrant = "platform:*"
)

Platform base permissions — the native `platform:` directory catalog (#95). These manage ENTITIES (accounts, orgs as whole units, the platform-admin roster), never an org's internals. super-admin = `platform:*` covers them all.

View Source
const (
	MemberKindUser              = "user"
	MemberKindRemoteApplication = "remote_application"
)

MemberKindRemoteApplication is the polymorphic org_memberships.member_kind for a remote_application principal. MemberKindUser is the user principal.

View Source
const (
	// ServiceJWTTokenUse is the required `token_use` claim for service JWTs.
	ServiceJWTTokenUse = "service"
	// ServiceJWTType is the JOSE typ header AuthKit stamps on minted service JWTs.
	ServiceJWTType = "service+jwt"
	// DefaultServiceJWTLifetime is the recommended lifetime for first-party
	// machine-to-machine service JWTs.
	DefaultServiceJWTLifetime = 15 * time.Minute
)
View Source
const (
	RemoteAppModeJWKS   = "jwks"
	RemoteAppModeStatic = "static"
)

Remote-application trust modes (#74). A remote_application is a federation PRINCIPAL whose credential is a key, with exactly one trust source:

jwks   — keys fetched + refreshed from JWKSURI; rotation is publishing a new
         kid at the same URL.
static — authorized_keys-style human-managed PEM list for principals without
         a JWKS endpoint; manual rotation by design.
View Source
const (
	SolanaSNSStatusDisabled = "disabled"
	SolanaSNSStatusPending  = "pending"
	SolanaSNSStatusResolved = "resolved"
	SolanaSNSStatusNotFound = "not_found"
	SolanaSNSStatusError    = "error"
	SolanaSNSStatusStale    = "stale"
)
View Source
const DefaultBootstrapManifestPath = "/etc/authkit/bootstrap.yaml"
View Source
const DelegatedAccessTokenType = jwtkit.DelegatedAccessTokenType

DelegatedAccessTokenType is the canonical JOSE `typ` header value for a delegated access token.

View Source
const HashAlgoLegacyResetRequired = "legacy-reset-required"

HashAlgoLegacyResetRequired marks profiles.user_passwords rows migrated from legacy systems whose stored hashes can never verify (DES crypt, md5-crypt, corrupted values). The raw legacy hash is preserved in password_hash for forensics only; the sole way forward for these accounts is a password reset.

View Source
const (
	// MaxCustomJWTLifetime caps the TTL of a custom-claims JWT. Custom tokens are
	// short-lived first-party tokens (capability/worker tokens, etc.); they share
	// the same 1h ceiling regardless of the requested TTL. Mirrors the bounded-TTL
	// guardrails on MintServiceJWT / MintDelegatedAccessToken.
	MaxCustomJWTLifetime = time.Hour
)
View Source
const PlatformSuperAdminRole = "super-admin"

PlatformSuperAdminRole is the conventional name of the seeded apex role.

View Source
const RemoteApplicationAccessTokenType = jwtkit.RemoteApplicationAccessTokenType

RemoteApplicationAccessTokenType is the JOSE `typ` for a remote application access token.

View Source
const SensitiveActionFreshAuthWindow = 15 * time.Minute
View Source
const SolanaProviderSlug = "solana"

SolanaProviderSlug is the provider slug used for Solana wallets.

Variables

View Source
var (
	// ErrInvalidAccessToken indicates an API key that does not exist, has a bad
	// secret, or whose owning org is gone. Deliberately indistinguishable from
	// a malformed token so callers learn nothing from the error.
	ErrInvalidAccessToken = errors.New("invalid_token")
	// ErrAccessTokenRevoked indicates the API key was explicitly revoked.
	ErrAccessTokenRevoked = errors.New("token_revoked")
	// ErrAccessTokenExpired indicates the API key is past its expires_at.
	ErrAccessTokenExpired = errors.New("token_expired")
)
View Source
var (
	// ErrEmptyCustomClaims is returned when CustomJWTMintOptions.Claims is empty —
	// MintCustomJWT exists to carry host claims, so an empty set is a caller bug.
	ErrEmptyCustomClaims = errors.New("custom_jwt_empty_claims")
	// ErrTooManyCustomClaims is returned when the host claim set exceeds
	// maxCustomJWTClaims.
	ErrTooManyCustomClaims = errors.New("custom_jwt_too_many_claims")
	// ErrCustomClaimsReserved is returned when the host Claims map tries to set a
	// registered claim that AuthKit owns (`iss`/`iat`/`exp`) — those are set by
	// AuthKit and the raw map may not silently clobber them. Use the explicit
	// Issuer option to override `iss`.
	ErrCustomClaimsReserved = errors.New("custom_jwt_reserved_claim")
)
View Source
var (
	// ErrAttributeDefNotFound indicates no registered definition matched.
	ErrAttributeDefNotFound = errors.New("attribute_def_not_found")
	// ErrInvalidAttributeDef indicates a malformed definition registration.
	ErrInvalidAttributeDef = errors.New("invalid_attribute_def")
)
View Source
var (
	// ErrUserBanned indicates the account is blocked from authenticating.
	ErrUserBanned = errors.New("user_banned")
	// ErrPasswordResetRequired indicates the account's stored password hash is
	// flagged HashAlgoLegacyResetRequired: no plaintext can ever verify against
	// it, so the user must complete a password reset before password auth (login,
	// reauth, change-password) can succeed. HTTP layers map this to the stable
	// code "password_reset_required".
	ErrPasswordResetRequired = errors.New("password_reset_required")
	// ErrUserNotFound indicates a user does not exist (or is not visible).
	ErrUserNotFound = errors.New("user_not_found")
	// ErrEmailAlreadyVerified indicates an email verification request targeted an already-verified email.
	ErrEmailAlreadyVerified = errors.New("email_already_verified")
	// ErrPhoneAlreadyVerified indicates a phone verification request targeted an already-verified phone.
	ErrPhoneAlreadyVerified = errors.New("phone_already_verified")
	// ErrPendingRegistrationNotFound indicates a registration resend request did not match a pending registration.
	ErrPendingRegistrationNotFound = errors.New("pending_registration_not_found")
	// ErrRegistrationDisabled indicates a public user-creation path was attempted
	// while native-user registration is bootstrap-only. Existing-user
	// authentication is unaffected; only NEW account creation through
	// public/auto-registration is blocked.
	ErrRegistrationDisabled = errors.New("registration_disabled")
	// ErrVerificationLinkExpired indicates a verification link/token no longer has a pending verification record.
	ErrVerificationLinkExpired = errors.New("verification_link_expired")
	// ErrOrgManagementDisabled indicates a public org onboarding/management path
	// was attempted while org registration is bootstrap-only. Embedded
	// bootstrap/admin core APIs remain available.
	ErrOrgManagementDisabled = errors.New("org_management_disabled")
)
View Source
var (
	ErrEmailDeliveryFailed = errors.New("email_delivery_failed")
	ErrSMSDeliveryFailed   = errors.New("sms_delivery_failed")
)
View Source
var (
	ErrInvalidServiceJWT = errors.New("invalid_service_jwt")
	ErrMissingSigner     = errors.New("missing_signer")
)
View Source
var (
	ErrOrgNotFound      = errors.New("org_not_found")
	ErrNotOrgMember     = errors.New("not_org_member")
	ErrInvalidOrgSlug   = errors.New("invalid_org_slug")
	ErrInvalidOrgRole   = errors.New("invalid_org_role")
	ErrInvalidOrgOwner  = errors.New("invalid_org_owner")
	ErrOrgLimitExceeded = errors.New("org_limit_exceeded")
	ErrProtectedOrgRole = errors.New("protected_org_role")
	ErrLastOrgOwner     = errors.New("cannot_remove_last_owner")
	ErrPersonalOrgOwner = errors.New("cannot_remove_personal_org_owner")
	// ErrRenameRateLimited is returned when a rename attempt happens
	// within renameCooldown of the previous rename for the same row.
	// Admin override paths (RenameOrgSlugForce / RenameUsernameForce)
	// bypass the check.
	ErrRenameRateLimited = errors.New("rename_rate_limited")
)
View Source
var (
	ErrOwnerSlugTaken    = errors.New("owner_slug_taken")
	ErrPersonalOrgLocked = errors.New("personal_org_locked")
	ErrInviteNotFound    = errors.New("org_invite_not_found")
	ErrInviteNotPending  = errors.New("org_invite_not_pending")
	ErrInviteNotForUser  = errors.New("org_invite_not_for_user")
	ErrInviteExpired     = errors.New("org_invite_expired")
	// ErrInviteRoleExceedsGrantor is returned when an invite's role confers
	// permissions the inviter does not (currently) hold — the no-escalation
	// invariant. Enforced at invite-create time and re-checked at accept time
	// (the inviter may have been demoted in between).
	ErrInviteRoleExceedsGrantor = errors.New("org_invite_role_exceeds_grantor")
	ErrPersonalOrgNotFound      = errors.New("personal_org_not_found")
)
View Source
var (
	ErrOwnerNamespaceNotFound          = errors.New("owner_namespace_not_found")
	ErrInvalidOwnerNamespaceState      = errors.New("invalid_owner_namespace_state")
	ErrInvalidOwnerNamespaceTransition = errors.New("invalid_owner_namespace_transition")
	ErrOwnerMembershipRequired         = errors.New("owner_membership_required")
	ErrOwnerNamespaceAlreadyClaimed    = errors.New("owner_namespace_already_claimed")
	ErrOwnerNamespaceBatchEmpty        = errors.New("owner_namespace_batch_empty")
)
View Source
var (
	// ErrRemoteApplicationNotFound indicates no remote_application matched.
	ErrRemoteApplicationNotFound = errors.New("remote_application_not_found")
	// ErrInvalidRemoteApplication indicates a malformed registration payload.
	ErrInvalidRemoteApplication = errors.New("invalid_remote_application")
)
View Source
var (
	ErrReservedAccountNotFound = errors.New("reserved_account_not_found")
	ErrReservedAccountClaimed  = errors.New("reserved_account_claimed")
)
View Source
var ErrCannotRemoveLastAdminRole = errors.New("cannot_remove_last_admin_role")

ErrCannotRemoveLastAdminRole is retained for the admin HTTP adapter's error mapping. The platform layer has no "last admin" lock (super-admin is seeded out-of-band via the bootstrap manifest), so core no longer returns it, but the exported symbol stays so dependents keep compiling.

View Source
var ErrEntitlementFilterUnavailable = errors.New("authkit: entitlement filtering requires an EntitlementFilterProvider")

ErrEntitlementFilterUnavailable is returned by AdminListUsers/AdminCountUsers when an Entitlement filter is requested but no EntitlementFilterProvider is configured — fail loud rather than silently return everyone.

View Source
var ErrInvalidBootstrapManifest = errors.New("invalid_bootstrap_manifest")
View Source
var ErrInvalidOrgManifest = errors.New("invalid_org_manifest")
View Source
var ErrReauthenticationRequired = errors.New("reauth_required")
View Source
var ErrRecoverInvalid = errors.New("recover requires an org and a new owner user")

ErrRecoverInvalid indicates a recover request is missing the org or new owner.

View Source
var ErrReservedRoleSlug = errors.New("reserved_role_slug")
View Source
var ErrUnknownPermission = errors.New("unknown_permission")

ErrUnknownPermission indicates a permission not present in the catalog.

View Source
var ErrUserRoleNotFound = errors.New("user_role_not_found")

Functions

func APIKeyMarker added in v0.41.0

func APIKeyMarker(prefix string) string

APIKeyMarker returns the leading marker that identifies an API key for the given application prefix: "<prefix>_st_" when prefix is non-empty, else "st_".

func BaseReservedPermissions added in v0.18.1

func BaseReservedPermissions() []string

BaseReservedPermissions lists authkit's own reserved base permissions — the concrete names hosts must include in the catalog they validate seeds against.

func EffectivePermsForTokens added in v0.18.1

func EffectivePermsForTokens(tokens []string, catalog map[string]bool) map[string]bool

EffectivePermsForTokens is the EXPORTED token evaluator: it expands one role's stored grant tokens against a catalog exactly the way authkit resolves permissions at request time (literals + namespace-anchored globs; no negation, no bare `*`; #93/#95).

Hosts should use THIS function in security tests that lock their seeded role definitions, instead of replicating the semantics: a replicated evaluator drifts, and drift in permission semantics fails silently.

func FormatAPIKey added in v0.41.0

func FormatAPIKey(prefix, keyID, secret string) string

FormatAPIKey assembles the full presented token: <marker><key_id>_<secret>.

func HasAPIKeyPrefix added in v0.41.0

func HasAPIKeyPrefix(prefix, token string) bool

HasAPIKeyPrefix reports whether token carries the API-key marker for prefix. Used by middleware to route to the API-key path before attempting JWT verification.

func IsAPIKeyGrantableReservedPermission added in v0.41.0

func IsAPIKeyGrantableReservedPermission(name string) bool

IsAPIKeyGrantableReservedPermission reports whether a reserved `org:` permission may be granted to an API key. Only READ actions qualify: an API key can never hold a write/manage perm, so it can never mint another API key, redefine roles, or alter membership — read-only automation (monitoring/audit bots) is the only escalation-harmless case. Accepts literals (`org:roles:read`) and read globs (`org:*:read`). Returns false for non-reserved names.

func IsDevEnvironment

func IsDevEnvironment(environment string) bool

IsDevEnvironment reports whether a host-provided environment string is non-production.

func IsPlatformPermission added in v0.42.0

func IsPlatformPermission(name string) bool

IsPlatformPermission reports whether name is in the `platform:` namespace.

func IsReservedPermission added in v0.11.3

func IsReservedPermission(name string) bool

IsReservedPermission reports whether name is in authkit's reserved base namespace (an app catalog may not redefine the base resource names; API keys may not hold the write actions, see IsAPIKeyGrantableReservedPermission).

func MintDelegatedAccessToken added in v0.26.0

func MintDelegatedAccessToken(ctx context.Context, signer jwtkit.Signer, p DelegatedAccessParams) (string, error)

MintDelegatedAccessToken signs a canonical delegated access token with an explicit signer. It stamps the `typ=delegated-access+jwt` JOSE header, writes the canonical `delegated_sub`/`permissions`/`attributes` claims, and NEVER sets `sub` — the sub-XOR-delegated_sub invariant is enforced by construction. Receiving services authorize by issuer/resource-account trust plus `permissions`. A top-level `roles` claim is never minted; delegated-subject role UUIDs, when carried, ride under `attributes.roles` (see the Roles param).

Hosts embedding core.Service should prefer (*Service).MintDelegatedAccessToken so they never construct their own signer or read the PEM.

func MintRemoteApplicationAccessToken added in v0.28.0

func MintRemoteApplicationAccessToken(ctx context.Context, signer jwtkit.Signer, p RemoteApplicationAccessParams) (string, error)

MintRemoteApplicationAccessToken signs a remote application access token with an explicit signer. It stamps the `typ=remote-application-access+jwt` header and writes NO `sub`/`delegated_sub` — identity is the validated `iss` and authority is STORED, resolved at verify. A non-nil p.Permissions is written as the `permissions` claim: a down-scoping request the verifier intersects with the stored ceiling (#76 amendment); never a widening.

func NormalizeAllowedOrigin added in v0.37.6

func NormalizeAllowedOrigin(origin string) (string, error)

NormalizeAllowedOrigin validates one browser Origin value and returns its canonical exact-match form. It accepts only scheme+host(+port), never paths, queries, fragments, userinfo, wildcards, or the special "null" origin.

func NormalizeAllowedOrigins added in v0.37.6

func NormalizeAllowedOrigins(origins []string) ([]string, error)

NormalizeAllowedOrigins validates, trims, normalizes, and de-duplicates exact browser origins for a remote_application.

func NormalizeEmail added in v0.8.6

func NormalizeEmail(email string) string

func NormalizePhone added in v0.8.6

func NormalizePhone(phone string) string

func NormalizePreferredLocale added in v0.14.0

func NormalizePreferredLocale(locale string) (string, error)

func NormalizeRemoteAppTrustSource added in v0.27.0

func NormalizeRemoteAppTrustSource(jwksURI string, mode string, keys []RemoteAppKey) (string, error)

NormalizeRemoteAppTrustSource validates the mutually-exclusive trust source of a registration and returns the normalized mode. Empty mode is inferred: a key list means static, otherwise jwks. It is the single validation gate so the XOR rule cannot be bypassed.

func OriginAllowed added in v0.37.6

func OriginAllowed(origin string, allowedOrigins []string) bool

OriginAllowed reports whether origin exactly matches one of allowedOrigins.

func OwnerSlugFromUsername added in v0.8.6

func OwnerSlugFromUsername(username string) string

func ParseAPIKey added in v0.41.0

func ParseAPIKey(prefix, token string) (keyID, secret string, ok bool)

ParseAPIKey splits a presented token into its key_id and secret. key_id and secret are base62 (no underscores), so the first "_" after the marker is the unambiguous delimiter. ok is false if the token lacks the marker or either part is empty.

func PermissionTokenCovers added in v0.42.0

func PermissionTokenCovers(grant, requested string) bool

PermissionTokenCovers reports whether a stored grant token covers a requested permission token using AuthKit's namespace-anchored glob semantics.

func UnknownRoleTokenNames added in v0.18.1

func UnknownRoleTokenNames(tokens []string, catalog map[string]bool) []string

UnknownRoleTokenNames returns every grant token that expands to NOTHING in the catalog (a bare `*`, a typo'd literal, or a glob matching no catalog perm) — validate seeds with this at startup or in tests and treat a non-empty result as a hard error so a role never references a permission that doesn't exist.

func UsernameOwnerNamespaceError added in v0.8.6

func UsernameOwnerNamespaceError(lookup *OwnerNamespaceLookup, allowedUserID string) string

func ValidateEmail added in v0.8.6

func ValidateEmail(email string) error

func ValidatePassword added in v0.8.6

func ValidatePassword(value string) error

func ValidatePhone added in v0.8.6

func ValidatePhone(phone string) error

func ValidateUsername added in v0.8.6

func ValidateUsername(username string) error

func ValidationErrorCode added in v0.8.6

func ValidationErrorCode(err error) string

ValidationErrorCode returns a stable validation code from err when possible.

func WithSessionRevokeReason

func WithSessionRevokeReason(ctx context.Context, reason SessionRevokeReason) context.Context

WithSessionRevokeReason annotates ctx so revoke paths can emit a structured reason to the auth logger.

Types

type APIKey added in v0.41.0

type APIKey struct {
	ID          string
	KeyID       string
	Name        string
	Permissions []string
	Resources   []APIKeyResource
	CreatedBy   string
	CreatedAt   time.Time
	LastUsedAt  *time.Time
	ExpiresAt   *time.Time
	RevokedAt   *time.Time
}

APIKey is the non-secret metadata view of an API key. The secret is never stored or returned after creation.

type APIKeyMintOptions added in v0.41.0

type APIKeyMintOptions struct {
	Name        string
	Permissions []string
	Resources   []APIKeyResource
	CreatedBy   string
	ExpiresAt   *time.Time
}

APIKeyMintOptions is the resource-aware API-key mint request. The token format remains unchanged; resources are stored beside the opaque credential.

type APIKeyResource added in v0.41.0

type APIKeyResource struct {
	Kind string `json:"kind"`
	ID   string `json:"id"`
}

APIKeyResource is one opaque, host-defined resource scope carried by an API key. AuthKit stores and returns the exact Kind/ID pair but does not interpret it. Hosts own resource semantics, including any wildcard-looking IDs such as "*".

type AdminListUsersResult

type AdminListUsersResult struct {
	Users  []AdminUser `json:"users"`
	Total  int64       `json:"total"`
	Limit  int         `json:"limit"`
	Offset int         `json:"offset"`
}

AdminListUsersResult contains paginated user list with total count

type AdminUser

type AdminUser struct {
	ID              string     `json:"id"`
	Email           *string    `json:"email"` // Nullable for phone-only users
	PhoneNumber     *string    `json:"phone_number"`
	Username        *string    `json:"username"`
	DiscordUsername *string    `json:"discord_username"`
	EmailVerified   bool       `json:"email_verified"`
	PhoneVerified   bool       `json:"phone_verified"`
	BannedAt        *time.Time `json:"banned_at,omitempty"`
	BannedUntil     *time.Time `json:"banned_until,omitempty"`
	BanReason       *string    `json:"ban_reason,omitempty"`
	BannedBy        *string    `json:"banned_by,omitempty"`
	DeletedAt       *time.Time `json:"deleted_at"`
	Biography       *string    `json:"biography"`
	CreatedAt       time.Time  `json:"created_at"`
	UpdatedAt       time.Time  `json:"updated_at"`
	LastLogin       *time.Time `json:"last_login"`
	Roles           []string   `json:"roles"`
	Entitlements    []string   `json:"entitlements"`
}

Admin listing/get/delete

type AdminUserListOptions added in v0.40.0

type AdminUserListOptions struct {
	Page        int
	PageSize    int
	Search      string          // ILIKE over username/email/phone_number
	Role        string          // global-role slug (e.g. "admin"); empty = no role filter
	OrgSlug     string          // org membership; empty = no org filter
	Status      AdminUserStatus // empty = non-deleted (historical default)
	Sort        AdminUserSort   // empty = created_at
	Desc        bool            // true = descending
	Entitlement string          // empty = no entitlement filter; else provider-backed
}

AdminUserListOptions is the GENERIC admin user-directory query (issue #91). It carries no host product knowledge: Role is any global-role slug, OrgSlug is any org slug, Status/Sort are closed enums. Entitlement filtering delegates to the billing provider (EntitlementFilterProvider), never a cross-schema join.

type AdminUserSort added in v0.40.0

type AdminUserSort string

AdminUserSort selects the directory ordering column.

const (
	AdminUserSortCreatedAt AdminUserSort = "created_at" // default
	AdminUserSortLastLogin AdminUserSort = "last_login"
	AdminUserSortUsername  AdminUserSort = "username"
	AdminUserSortEmail     AdminUserSort = "email"
)

type AdminUserStatus added in v0.40.0

type AdminUserStatus string

AdminUserStatus filters the directory by account state.

const (
	AdminUserStatusActive  AdminUserStatus = "active"  // not deleted, not banned
	AdminUserStatusBanned  AdminUserStatus = "banned"  // not deleted, currently banned
	AdminUserStatusDeleted AdminUserStatus = "deleted" // soft-deleted
	AdminUserStatusAny     AdminUserStatus = "any"     // no deleted/banned predicate

)

type AuthEventLogReader added in v0.4.2

type AuthEventLogReader interface {
	// ListSessionEvents returns session events matching any of the given event types.
	// If userID is empty, returns events for all users.
	ListSessionEvents(ctx context.Context, userID string, eventTypes ...SessionEventType) ([]AuthSessionEvent, error)
}

AuthEventLogReader allows listing session events filtered by event types and optional userID.

type AuthEventLogger

type AuthEventLogger interface {
	LogSessionEvent(ctx context.Context, e AuthSessionEvent) error
}

type AuthSessionEvent

type AuthSessionEvent struct {
	OccurredAt time.Time
	Issuer     string
	UserID     string
	SessionID  string
	Event      SessionEventType
	Method     *string
	Reason     *string
	IPAddr     *string
	UserAgent  *string
}

AuthSessionEvent is a best-effort, append-only session lifecycle record intended for external sinks.

ClickHouse schema expectation (see migrations/clickhouse): - issuer, user_id, session_id, event are required - method is typically set for SessionEventCreated - reason is typically set for SessionEventRevoked

type BatchEntitlementsProvider added in v0.21.0

type BatchEntitlementsProvider interface {
	ListEntitlementsBatch(ctx context.Context, userIDs []string) (map[string][]string, error)
}

BatchEntitlementsProvider is an optional upgrade of EntitlementsProvider: one call answers many users, so list renders (AdminListUsers) cost one provider round trip instead of one per row. Detected by type assertion; providers without it get the per-user fallback. Unknown user ids may be absent from the result.

type BootstrapAPIKeyOutput added in v0.41.0

type BootstrapAPIKeyOutput = OrgManifestAPIKeyOutput

type BootstrapManifest added in v0.37.0

type BootstrapManifest struct {
	Users       []BootstrapManifestUser       `json:"users" yaml:"users"`
	GlobalRoles []BootstrapManifestGlobalRole `json:"global_roles" yaml:"global_roles"`
	Orgs        []OrgManifestOrg              `json:"orgs" yaml:"orgs"`
}

BootstrapManifest is AuthKit's first-class closed-deployment authority manifest. It owns AuthKit state only: users, platform roles, orgs, org RBAC, trusted issuers, and generated API-key outputs.

The legacy "global roles" plane was hard-cut in favor of Layer-2 platform RBAC (profiles.platform_roles + `platform:*` perms). The manifest still uses the `global_roles` field names for backward compatibility, but they now seed and assign PLATFORM roles: a role named "admin" maps onto the seeded platform super-admin (platform:*), and any other name is defined as an empty platform role (no perms until set explicitly). The legacy role name/description fields no longer have a target column and are accepted-but-ignored.

func LoadBootstrapManifestFile added in v0.37.0

func LoadBootstrapManifestFile(path string) (BootstrapManifest, error)

func ParseBootstrapManifestYAML added in v0.37.0

func ParseBootstrapManifestYAML(raw []byte) (BootstrapManifest, error)

type BootstrapManifestGlobalRole added in v0.37.0

type BootstrapManifestGlobalRole struct {
	Name        string  `json:"name" yaml:"name"`
	Slug        string  `json:"slug" yaml:"slug"`
	Description *string `json:"description" yaml:"description"`
}

BootstrapManifestGlobalRole declares a platform role to define. Only Slug is meaningful now (the role name); Name/Description are accepted for backward compatibility but ignored, since platform roles have no name/description columns. "admin" seeds the super-admin role (platform:*).

type BootstrapManifestResult added in v0.37.0

type BootstrapManifestResult struct {
	DryRun                bool              `json:"dry_run"`
	UsersCreated          int               `json:"users_created"`
	UsersUpdated          int               `json:"users_updated"`
	PasswordsSet          int               `json:"passwords_set"`
	PasswordsKept         int               `json:"passwords_kept"`
	GlobalRoles           int               `json:"global_roles"`
	GlobalRoleAssignments int               `json:"global_role_assignments"`
	OrgManifest           OrgManifestResult `json:"org_manifest"`
}

type BootstrapManifestUser added in v0.37.0

type BootstrapManifestUser struct {
	Ref           string                 `json:"ref" yaml:"ref"`
	Email         string                 `json:"email" yaml:"email"`
	PhoneNumber   string                 `json:"phone_number" yaml:"phone_number"`
	Username      string                 `json:"username" yaml:"username"`
	EmailVerified bool                   `json:"email_verified" yaml:"email_verified"`
	PhoneVerified bool                   `json:"phone_verified" yaml:"phone_verified"`
	Banned        bool                   `json:"banned" yaml:"banned"`
	BannedAt      *time.Time             `json:"banned_at" yaml:"banned_at"`
	BannedUntil   *time.Time             `json:"banned_until" yaml:"banned_until"`
	BanReason     *string                `json:"ban_reason" yaml:"ban_reason"`
	BannedBy      *string                `json:"banned_by" yaml:"banned_by"`
	Metadata      map[string]any         `json:"metadata" yaml:"metadata"`
	Password      *BootstrapUserPassword `json:"password" yaml:"password"`
	// GlobalRoles assigns platform roles to this user by name (hard-cut: was the
	// legacy global-roles plane). "admin" mints the platform super-admin
	// (platform:*); any other name is assigned as a same-named platform role.
	GlobalRoles []string `json:"global_roles" yaml:"global_roles"`
}

type BootstrapReconcileOptions added in v0.37.0

type BootstrapReconcileOptions struct {
	DryRun bool
}

type BootstrapTokenStore added in v0.37.0

type BootstrapTokenStore = OrgManifestTokenStore

type BootstrapUserPassword added in v0.37.0

type BootstrapUserPassword struct {
	Plaintext     string         `json:"plaintext" yaml:"plaintext"`
	Hash          string         `json:"hash" yaml:"hash"`
	HashAlgo      string         `json:"hash_algo" yaml:"hash_algo"`
	HashParams    map[string]any `json:"hash_params" yaml:"hash_params"`
	ResetRequired bool           `json:"reset_required" yaml:"reset_required"`
	// Enforce makes the password DESIRED-STATE (#89): re-asserted on every
	// reconcile. Default false = SEED-ONCE — the password is applied only when
	// the user is first created, so a password rotated out of band (via the
	// admin API) is never reverted to the manifest value on a later reconcile.
	// Must not be combined with ResetRequired (forcing a reset every run is
	// nonsensical).
	Enforce bool `json:"enforce" yaml:"enforce"`
}

type Config

type Config struct {
	Issuer               string
	IssuedAudiences      []string // JWT audiences - tokens issued will contain ALL of these audiences
	ExpectedAudiences    []string
	AccessTokenDuration  time.Duration
	RefreshTokenDuration time.Duration
	// Session limits
	SessionMaxPerUser int // 0 = unlimited, default 3 if unset by service; eviction is always evict-oldest
	// Optional: if set, used for building absolute URLs (e.g., password reset/verify links).
	// If empty and Issuer is a well-formed URL, NewFromConfig defaults BaseURL to Issuer.
	BaseURL string
	// FrontendCallbackPath is the host-owned frontend route that receives full-page
	// OIDC login results. Empty defaults to "/login/callback".
	FrontendCallbackPath string

	// Schema is the Postgres schema AuthKit's tables live in. Empty defaults to
	// "profiles" (the historical hard-coded name), which is fully
	// backward-compatible. Set it when multiple apps embed AuthKit against the
	// same database and must not share auth tables (authkit issue 69). The name
	// must match ^[a-z_][a-z0-9_]*$ (max 63 bytes); NewFromConfig rejects
	// anything else. Hosts that set a non-default schema must also run the
	// migrations rendered for that schema — see migrations/postgres.FSForSchema.
	Schema string

	// RegistrationVerification controls registration verification behavior.
	// Valid values: "none", "optional", "required".
	// Empty defaults to "none".
	RegistrationVerification RegistrationVerificationPolicy

	// AutoCreatePersonalOrgs creates a personal org for each native user at
	// signup. Direct host opt-in (authkit issue 60): orgs are always a supported
	// primitive, so this is no longer gated on a global org mode. Empty/false
	// means native users can exist without org rows; hosts that want
	// personal/team workspaces opt in.
	AutoCreatePersonalOrgs bool

	// NativeUserRegistrationMode controls public native-user self-registration.
	// Empty defaults to "open". Non-open modes disable every public user
	// creation path while leaving embedded admin/bootstrap core APIs available.
	NativeUserRegistrationMode RegistrationMode

	// OrgRegistrationMode controls public org onboarding/management.
	// Empty defaults to "open". Non-open modes disable public org mutation
	// routes while leaving manifest/admin/bootstrap core APIs available.
	OrgRegistrationMode RegistrationMode

	// Environment is a host-provided runtime mode string used for dev/prod behavior checks.
	// Expected values include "prod"/"production" for production, anything else is treated as non-prod.
	Environment string

	// SolanaNetwork is a host-provided Solana chain selector ("mainnet", "testnet", "devnet").
	// If empty, AuthKit derives a default from Environment.
	SolanaNetwork string
	// SolanaSNSEnabled enables AuthKit-owned Solana Name Service resolution for SIWS-linked wallets.
	SolanaSNSEnabled bool
	// SolanaSNSResolver resolves a verified Solana wallet address to its primary .sol name.
	SolanaSNSResolver SolanaSNSResolver
	// SolanaSNSLookupTimeout bounds resolver calls. Empty defaults to 3 seconds.
	SolanaSNSLookupTimeout time.Duration
	// SolanaSNSCacheTTL controls when cached SNS metadata is considered stale. Empty defaults to 24 hours.
	SolanaSNSCacheTTL time.Duration

	// Keys can be nil - if nil, authkit auto-discovers keys with this priority:
	// 1. Environment variables (ACTIVE_KEY_ID, ACTIVE_PRIVATE_KEY_PEM, PUBLIC_KEYS)
	// 2. Filesystem <KeysPath>/keys.json (default /vault/auth; External Secrets
	//    Operator in K8s). Override the directory with KeysPath or the
	//    AUTHKIT_KEYS_PATH env var.
	// 3. Auto-generated keys in .runtime/authkit/ (development fallback; prod hard-fail)
	//
	// Hosts NEVER handle the private key: they delegate the signing OPERATION to
	// authkit (the Service mint methods / the internal Signer). There is no API
	// that returns a private key or PEM. A future remote Vault-Transit backend
	// (authkit future #72) drops in behind the same Signer seam with no host
	// changes.
	Keys jwtkit.KeySource

	// VerifyOnly constructs the Service with NO active signer (#87): token
	// MINTING (IssueAccessToken, MintServiceJWT/MintCustomJWT/
	// MintDelegatedAccessToken, remote application access tokens) returns
	// ErrMissingSigner, while VERIFICATION and all RBAC reads work fully and the
	// JWKS endpoint serves an empty key set. When true, key auto-discovery is
	// SKIPPED — no env/file/dev key is required to boot. Ignored when Keys is
	// non-nil (an explicit KeySource wins). Use it for a pure resource-server /
	// control-plane deployment that only verifies inbound tokens (e.g. OpenRails
	// standalone with no login-capable users).
	VerifyOnly bool

	// KeysPath overrides the filesystem DIRECTORY the local key resolver scans
	// for keys.json when Keys is nil. Empty defaults to the AUTHKIT_KEYS_PATH
	// env var, then to /vault/auth, so existing embedders are unchanged. Use it
	// when the host renders its keyset outside K8s (e.g. a host-run dev mount).
	KeysPath string

	// Providers – identity providers by name ("google", "apple", "github", "discord").
	// Only client id/secret are required; standard scopes are derived from defaults.
	Providers map[string]oidckit.RPConfig

	// ProviderDescriptors define OAuth2/OIDC providers using config-first
	// descriptors. These augment/override built-in Providers entries and are
	// the preferred path for adding custom providers.
	ProviderDescriptors map[string]authprovider.Provider

	// APIKeyPrefix is the issuing application's brand prefix for generated API
	// keys. It is a single value per deployment (NOT per-org) and a free brand
	// choice by the host app. Empty defaults to the legacy bare `st_` marker.
	// Must be lowercase alphanumeric, 1-16 chars. A unique app prefix lets leak
	// scanners and push-protection partners identify the issuer at a glance.
	APIKeyPrefix string

	// APIKeyMaxTTL caps how far in the future a minted API key may expire.
	// 0 (default) means no cap (keys may be non-expiring). When set, a
	// requested expiry beyond now+MaxTTL — including a null/no-expiry request —
	// is capped to now+MaxTTL at mint time.
	APIKeyMaxTTL time.Duration

	// ResourceScopeAuthorizer optionally authorizes host-defined API-key resource
	// scopes during HTTP minting. AuthKit validates only shape/length and stores
	// resource Kind/ID pairs opaquely; the embedding host owns semantic
	// no-escalation such as "may this caller mint openrails.customer=cozy-art".
	ResourceScopeAuthorizer ResourceScopeAuthorizer

	// Permissions is the embedding application's set of valid permission
	// strings (e.g. tensorhub's `endpoint:revise`, `repo:create`). authkit merges
	// this with its own base permissions (the reserved `org:` namespace) to form
	// the permission set it validates role/API-key grants against. Permissions
	// are opaque to authkit — it never interprets their meaning. Names must not
	// collide with the reserved `org:` base permissions.
	Permissions []PermissionDef

	// DefaultRoles are role templates seeded into every org at creation, in
	// addition to the built-in `owner` role (which is always seeded with
	// `org:*`). Permission tokens are concrete perms (`org:members:read`) or
	// namespace-anchored globs (`org:*`, `org:members:*`, `org:*:read`). There
	// is NO bare `*` and NO `!perm` negation — positive grants only (#93/#95).
	// e.g. a least-privilege `admin` = {"org:members:*", "org:roles:read"}.
	DefaultRoles []DefaultRole
}

Config mirrors the simplicity of go-pkgz/auth: provide issuer, durations, and keys.

type CreateOrgForUserRequest added in v0.30.0

type CreateOrgForUserRequest struct {
	Slug        string
	OwnerUserID string
}

CreateOrgForUserRequest is the public org-registration contract. The org is owned by a real authenticated user; ownerless org creation is reserved for privileged bootstrap/admin APIs.

type CustomJWTMintOptions added in v0.26.0

type CustomJWTMintOptions struct {
	// Claims is the host's claim set, e.g. {"cap_kind": "...", "grants": [...],
	// "release_id": "..."}. Required and non-empty. It may carry `sub`/`aud`
	// (unless overridden by the Subject/Audiences options) but may NOT carry the
	// AuthKit-owned registered claims `iss`/`iat`/`exp`.
	Claims map[string]any
	// TTL is the token lifetime. Required (must be > 0); capped at
	// MaxCustomJWTLifetime.
	TTL time.Duration
	// Type is the JOSE `typ` header (e.g. "worker-capability+jwt"). When empty the
	// header is left unset — unlike the opinionated minters, MintCustomJWT does
	// not impose a default `typ`; the host owns the token shape.
	Type string
	// Subject, when set, becomes the `sub` claim and wins over any `sub` in Claims.
	Subject string
	// Audiences, when set, becomes the `aud` claim and wins over any `aud` in Claims.
	Audiences []string
	// Issuer, when set, becomes the `iss` claim; otherwise `iss` defaults to the
	// Service's configured Issuer. This is the ONLY way to override `iss`.
	Issuer string
}

CustomJWTMintOptions controls minting of a JWT with an arbitrary first-party claim set. This is AuthKit's documented escape hatch: the HOST owns the claim semantics, and the verifier side MUST understand them. Prefer the constrained, opinionated paths — MintServiceJWT (machine-to-machine service JWT) and MintDelegatedAccessToken (cross-service delegated access) — whenever they fit; reach for MintCustomJWT only for token shapes those can't express (e.g. tensorhub capability/worker tokens with `cap_kind`/`grants`/`release_id`).

Claim precedence (documented + enforced):

  • AuthKit ALWAYS sets the registered claims it owns: `iss`, `iat`, `exp` (and the `kid`/`alg` JOSE headers, via the signer). The host Claims map may NOT set `iss`/`iat`/`exp` — doing so returns ErrCustomClaimsReserved rather than silently dropping or clobbering them.
  • `iss` is overridable ONLY via the explicit Issuer option (defaults to the Service's configured Issuer). `sub`/`aud` are set from the explicit Subject/Audiences options when provided; otherwise the host Claims map may carry its own `sub`/`aud` (the host owns those for custom tokens). When an explicit Subject/Audiences IS provided, it wins over any `sub`/`aud` in the Claims map.

type DefaultRole added in v0.11.3

type DefaultRole struct {
	Name        string   `json:"name"`
	Permissions []string `json:"permissions"`
}

DefaultRole is a role template seeded into every org at creation: a role name and its permission set (tokens are concrete perms or namespace-anchored globs like `org:*`/`org:*:read`; no bare `*`, no `!perm` negation).

type DelegatedAccessParams added in v0.26.0

type DelegatedAccessParams struct {
	// Issuer becomes the `iss` claim: the AuthKit issuer that signed the token.
	// Must match a remote_application registered with the validating resource server.
	// Required when minting via the free function; the *Service mint method
	// defaults it to the Service's configured Issuer when empty.
	Issuer string
	// Audiences becomes the `aud` claim: the target resource API(s), e.g.
	// "openrails", "tensorhub", or "gen-orchestrator".
	Audiences []string
	// DelegatedSubject becomes `delegated_sub`: the issuer-side subject id.
	// Required. No local account is implied in the receiving service.
	DelegatedSubject string
	// Permissions becomes the `permissions` claim: an array of resource-defined
	// permission strings (NOT OAuth's space-delimited `scope`). Receiving
	// services validate these against their own permission set.
	Permissions []string
	// Attributes becomes the `attributes` claim: the canonical app-specific
	// ESCAPE HATCH (#75). An object of issuer-asserted, NAMESPACED, OPAQUE
	// key/values that AuthKit transports + optionally shape-validates but NEVER
	// interprets — the semantics belong to the consuming app (tensorhub etc.).
	// Each value is set in ONE of two modes, per key:
	//   INLINE    — the value carries the full definition, e.g.
	//               {"tier":{"endpoints":[...],"caps":[...]}}. No lookup.
	//   REFERENCE — the value is a short string key, e.g. {"tier":"tier-1"},
	//               resolved by the consumer against a definition the
	//               remote_application registered ahead of time (see the
	//               attribute-def registry: Service.RegisterRemoteAppAttributeDef
	//               / ResolveRemoteAppAttributeDef). Keeps tokens small.
	// Reserved well-known keys: `tier` (opaque entitlement-tier string) and
	// `roles` (a uuid array; prefer the typed Roles field below). Everything
	// else is free-form per consuming app. Values are arbitrary JSON.
	Attributes map[string]any
	// Roles is a convenience for emitting the delegated subject's role UUIDs into
	// `attributes.roles` (a JSON array of UUID strings). Equivalent to setting
	// Attributes["roles"] yourself; when both are set this typed field wins.
	Roles []string
	// TTL is the token lifetime. Defaults to 15m when zero.
	TTL time.Duration
	// JTI, when set, becomes the `jti` claim (token identifier). Optional.
	JTI string
	// NotBefore, when set, becomes the `nbf` claim. Optional.
	NotBefore time.Time
}

DelegatedAccessParams describes a delegated access token to mint.

A delegated access token is AuthKit's standard primitive for resource-service federation: one AuthKit issuer signs a short-lived JWT for an external delegated subject, and a resource service accepts it after issuer/JWKS/ audience validation. The token represents a delegated subject (DelegatedSubject) acting under the resource account that the VALIDATED `iss` resolves to in the receiver's issuer registry — the token itself carries no org claims. It NEVER carries a normal `sub` — no local account is implied in the receiving service.

type EmailSender

type EmailSender interface {
	SendVerification(ctx context.Context, email, username string, msg VerificationMessage) error
	SendPasswordResetLink(ctx context.Context, email, username, token string) error
	SendLoginCode(ctx context.Context, email, username, code string) error
	SendWelcome(ctx context.Context, email, username string) error
}

EmailSender sends verification/login/reset emails.

type EntitlementFilterProvider added in v0.40.0

type EntitlementFilterProvider interface {
	ListSubjectsWithEntitlement(ctx context.Context, entitlement string) ([]string, error)
}

EntitlementFilterProvider is the REVERSE of EntitlementsProvider: given an entitlement key, it returns the subject ids that currently hold it. AuthKit owns the user DIRECTORY; the billing system (OpenRails) owns "who is entitled", so filtering the directory BY entitlement delegates here instead of joining across schemas. Subject ids ARE user ids (UUID-only payable identity). Detected by type assertion on the entitlements provider; when absent, AdminListUsers with an Entitlement filter fails with ErrEntitlementFilterUnavailable so the misconfiguration is loud rather than silently returning everyone.

type EntitlementsProvider

type EntitlementsProvider interface {
	ListEntitlements(ctx context.Context, userID string) ([]string, error)
}

EntitlementsProvider returns the names of a user's currently active application entitlements (e.g., billing tiers). Names are the ONLY shape AuthKit consumes — they are baked verbatim into the `entitlements` claim of access tokens and surfaced on admin user views. Providers should return active grants only; expired/revoked entitlements are the provider's concern, not AuthKit's.

type EphemeralMode

type EphemeralMode string
const (
	EphemeralMemory EphemeralMode = "memory"
	EphemeralRedis  EphemeralMode = "redis"
)

type EphemeralStore

type EphemeralStore interface {
	Get(ctx context.Context, key string) ([]byte, bool, error)
	Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
	Del(ctx context.Context, key string) error
}

EphemeralStore is a minimal key-value interface used for short-lived auth state. Implementations should honor TTL on Set and treat missing keys as (found=false, err=nil).

type FileBootstrapTokenStore added in v0.37.0

type FileBootstrapTokenStore = FileOrgManifestTokenStore

type FileOrgManifestTokenStore added in v0.30.0

type FileOrgManifestTokenStore struct{}

FileOrgManifestTokenStore writes tokens to local files. It intentionally refuses Vault outputs; production deployments can provide a Vault-backed OrgManifestTokenStore with narrower deploy-time credentials.

func (FileOrgManifestTokenStore) ReadOrgManifestToken added in v0.30.0

func (FileOrgManifestTokenStore) WriteOrgManifestToken added in v0.30.0

func (FileOrgManifestTokenStore) WriteOrgManifestToken(_ context.Context, out OrgManifestAPIKeyOutput, token string) error

type ImportUserInput added in v0.9.0

type ImportUserInput struct {
	Email         string
	PhoneNumber   string
	Username      string
	EmailVerified bool
	PhoneVerified bool
	BannedAt      *time.Time
	BannedUntil   *time.Time
	BanReason     *string
	BannedBy      *string
	Metadata      map[string]any
	CreatedAt     *time.Time
	UpdatedAt     *time.Time
}

type Keyset

type Keyset struct {
	Active     jwtkit.Signer
	PublicKeys map[string]crypto.PublicKey // kid -> pub
}

Keyset holds the active signer and the public keys exposed via JWKS.

type MintedOrgProvisionAPIKey added in v0.38.0

type MintedOrgProvisionAPIKey struct {
	Name      string
	Metadata  APIKey
	Plaintext string
	Output    OrgManifestAPIKeyOutput
}

MintedOrgProvisionAPIKey contains a plaintext generated API key. The value is returned only at creation time and should be written to a secret store by the caller.

type Options

type Options struct {
	Issuer               string
	IssuedAudiences      []string // JWT audiences - tokens issued will contain ALL of these audiences
	ExpectedAudiences    []string
	AccessTokenDuration  time.Duration
	RefreshTokenDuration time.Duration
	SessionMaxPerUser    int
	// Optional link building (paths are fixed: /reset and /verify)
	BaseURL string
	// FrontendCallbackPath is the host-owned frontend route that receives full-page OIDC login results.
	FrontendCallbackPath string
	// Schema is the Postgres schema AuthKit's tables live in. Empty defaults to
	// "profiles". Must match ^[a-z_][a-z0-9_]*$ (max 63 bytes); NewService
	// panics on an invalid non-empty value because a malformed name would be
	// spliced into SQL text (see internal/db.ForSchema). Prefer NewFromConfig,
	// which returns the validation error instead.
	Schema string
	// RegistrationVerification controls whether registration verification is disabled,
	// non-blocking, or required.
	RegistrationVerification RegistrationVerificationPolicy

	// VerificationSendTimeout bounds each in-line email/SMS provider send
	// (verification codes, password-reset links, login codes) so a configured
	// but misconfigured/unreachable provider cannot hang the request that
	// triggered it (e.g. registration). Empty/<=0 defaults to 15 seconds.
	VerificationSendTimeout time.Duration

	// AutoCreatePersonalOrgs creates a personal org for each native user at
	// signup (direct opt-in; authkit issue 60). False keeps native users
	// org-free by default.
	AutoCreatePersonalOrgs bool

	// NativeUserRegistrationMode controls public native-user self-registration.
	NativeUserRegistrationMode RegistrationMode
	// OrgRegistrationMode controls public org onboarding/management.
	OrgRegistrationMode RegistrationMode

	// Environment is host-provided runtime mode used for dev/prod behavior checks.
	Environment string
	// SolanaNetwork is host-provided chain selector for SIWS flows.
	SolanaNetwork string
	// SolanaSNSEnabled enables AuthKit-owned Solana Name Service resolution for SIWS-linked wallets.
	SolanaSNSEnabled bool
	// SolanaSNSResolver resolves a verified Solana wallet address to its primary .sol name.
	SolanaSNSResolver SolanaSNSResolver
	// SolanaSNSLookupTimeout bounds resolver calls. Empty defaults to 3 seconds.
	SolanaSNSLookupTimeout time.Duration
	// SolanaSNSCacheTTL controls when cached SNS metadata is considered stale. Empty defaults to 24 hours.
	SolanaSNSCacheTTL time.Duration

	// APIKeyPrefix is the issuing application's brand prefix for generated API
	// keys (validated lowercase-alnum, 1-16 chars; empty -> bare st_).
	APIKeyPrefix string
	// APIKeyMaxTTL caps a minted API key's expiry (0 = no cap).
	APIKeyMaxTTL time.Duration
	// ResourceScopeAuthorizer optionally authorizes host-defined API-key resource
	// scopes during HTTP minting. Nil means AuthKit stores valid scopes
	// opaquely for callers who may manage API keys for the org.
	ResourceScopeAuthorizer ResourceScopeAuthorizer
	// Permissions is the app's permission vocabulary (merged with authkit's
	// base `org:` permissions). DefaultRoles are role templates seeded per org.
	Permissions  []PermissionDef
	DefaultRoles []DefaultRole
}

Options configures issued tokens and identifiers.

func (Options) AutoCreatePersonalOrgsEnabled added in v0.30.0

func (o Options) AutoCreatePersonalOrgsEnabled() bool

func (Options) PublicNativeUserRegistrationEnabled added in v0.12.4

func (o Options) PublicNativeUserRegistrationEnabled() bool

PublicNativeUserRegistrationEnabled reports whether public native-user self-registration / auto-registration is allowed.

func (Options) PublicOrgRegistrationEnabled added in v0.30.0

func (o Options) PublicOrgRegistrationEnabled() bool

PublicOrgRegistrationEnabled reports whether public org onboarding / management HTTP routes are allowed.

func (Options) RegistrationVerificationEnabled added in v0.5.0

func (o Options) RegistrationVerificationEnabled() bool

func (Options) RegistrationVerificationPolicy added in v0.5.0

func (o Options) RegistrationVerificationPolicy() RegistrationVerificationPolicy

func (Options) RegistrationVerificationRequired added in v0.5.0

func (o Options) RegistrationVerificationRequired() bool

type Org added in v0.4.4

type Org struct {
	ID          string
	Slug        string
	IsPersonal  bool
	OwnerUserID string
}

Org is a minimal org record.

type OrgAdminDetail added in v0.42.0

type OrgAdminDetail struct {
	OrgAdminSummary
	MemberCount int64 `json:"member_count"`
}

OrgAdminDetail is the entity view of a single org (no internals).

type OrgAdminSummary added in v0.42.0

type OrgAdminSummary struct {
	ID          string     `json:"id"`
	Slug        string     `json:"slug"`
	IsPersonal  bool       `json:"is_personal"`
	OwnerUserID string     `json:"owner_user_id,omitempty"`
	CreatedAt   time.Time  `json:"created_at"`
	DeletedAt   *time.Time `json:"deleted_at,omitempty"`
}

OrgAdminSummary is one row of the org directory.

type OrgInvite added in v0.4.6

type OrgInvite struct {
	ID        string     `json:"id"`
	Org       string     `json:"org"`
	UserID    string     `json:"user_id"`
	InvitedBy string     `json:"invited_by"`
	Role      string     `json:"role"`
	Status    string     `json:"status"`
	ExpiresAt *time.Time `json:"expires_at,omitempty"`
	ActedAt   *time.Time `json:"acted_at,omitempty"`
	CreatedAt time.Time  `json:"created_at"`
}

type OrgManifest added in v0.30.0

type OrgManifest struct {
	Orgs []OrgManifestOrg `json:"orgs" yaml:"orgs"`
}

OrgManifest is the DevOps source of truth for closed-registration AuthKit deployments. It declares orgs plus their trusted OIDC issuers, roles, and optional server-to-server API keys.

func ParseOrgManifestYAML added in v0.30.0

func ParseOrgManifestYAML(raw []byte) (OrgManifest, error)

ParseOrgManifestYAML parses a org manifest and rejects unknown fields.

func ParseOrgManifestYAMLFile added in v0.30.0

func ParseOrgManifestYAMLFile(path string) (OrgManifest, error)

type OrgManifestAPIKey added in v0.38.0

type OrgManifestAPIKey struct {
	Name        string                  `json:"name" yaml:"name"`
	Permissions []string                `json:"permissions" yaml:"permissions"`
	Resources   []APIKeyResource        `json:"resources" yaml:"resources"`
	ExpiresAt   *time.Time              `json:"expires_at" yaml:"expires_at"`
	Output      OrgManifestAPIKeyOutput `json:"output" yaml:"output"`
}

OrgManifestAPIKey declares one generated opaque API key.

type OrgManifestAPIKeyOutput added in v0.38.0

type OrgManifestAPIKeyOutput struct {
	File       string `json:"file" yaml:"file"`
	VaultMount string `json:"vault_mount" yaml:"vault_mount"`
	VaultPath  string `json:"vault_path" yaml:"vault_path"`
	VaultField string `json:"vault_field" yaml:"vault_field"`
}

OrgManifestAPIKeyOutput names where a freshly minted API key should be written. AuthKit ships a file-backed implementation; Vault/Kubernetes/etc. can implement OrgManifestTokenStore with the same output struct.

type OrgManifestIssuer added in v0.30.0

type OrgManifestIssuer struct {
	Slug           string         `json:"slug" yaml:"slug"`
	Issuer         string         `json:"issuer" yaml:"issuer"`
	JWKSURI        string         `json:"jwks_uri" yaml:"jwks_uri"`
	Mode           string         `json:"mode" yaml:"mode"`
	PublicKeys     []RemoteAppKey `json:"public_keys" yaml:"public_keys"`
	Audiences      []string       `json:"audiences" yaml:"audiences"`
	AllowedOrigins []string       `json:"allowed_origins" yaml:"allowed_origins"`
	Role           string         `json:"role" yaml:"role"`
	Enabled        *bool          `json:"enabled" yaml:"enabled"`
}

type OrgManifestMembership added in v0.30.0

type OrgManifestMembership struct {
	UserID   string `json:"user_id" yaml:"user_id"`
	UserRef  string `json:"user_ref,omitempty" yaml:"user_ref,omitempty"`
	Username string `json:"username,omitempty" yaml:"username,omitempty"`
	Email    string `json:"email,omitempty" yaml:"email,omitempty"`
	Role     string `json:"role" yaml:"role"`
}

type OrgManifestOrg added in v0.30.0

type OrgManifestOrg struct {
	Slug        string                  `json:"slug" yaml:"slug"`
	Issuers     []OrgManifestIssuer     `json:"issuers" yaml:"issuers"`
	Roles       []OrgManifestRole       `json:"roles" yaml:"roles"`
	Memberships []OrgManifestMembership `json:"memberships" yaml:"memberships"`
	APIKeys     []OrgManifestAPIKey     `json:"api_keys" yaml:"api_keys"`
}

type OrgManifestResult added in v0.30.0

type OrgManifestResult struct {
	Orgs          int
	Issuers       int
	Roles         int
	Memberships   int
	APIKeysMinted int
	APIKeysKept   int
}

type OrgManifestRole added in v0.30.0

type OrgManifestRole struct {
	Name        string   `json:"name" yaml:"name"`
	Permissions []string `json:"permissions" yaml:"permissions"`
}

type OrgManifestTokenStore added in v0.30.0

type OrgManifestTokenStore interface {
	ReadOrgManifestToken(ctx context.Context, out OrgManifestAPIKeyOutput) (string, error)
	WriteOrgManifestToken(ctx context.Context, out OrgManifestAPIKeyOutput, token string) error
}

OrgManifestTokenStore preserves existing non-empty outputs and writes newly minted API-key values. The store owns the output backend.

type OrgMembership added in v0.4.4

type OrgMembership struct {
	Org   string
	Roles []string
}

OrgMembership is a user's membership with optional roles.

type OrgProvisionAPIKey added in v0.38.0

type OrgProvisionAPIKey struct {
	Name        string
	Permissions []string
	Resources   []APIKeyResource
	ExpiresAt   *time.Time
	CreatedBy   string
	Output      OrgManifestAPIKeyOutput
}

OrgProvisionAPIKey declares one generated opaque API key. When Output is empty, the plaintext token is returned in the result. When Output is non-empty and a store is supplied, existing non-empty output is preserved and no new token is minted.

type OrgProvisionIssuer added in v0.30.0

type OrgProvisionIssuer struct {
	Slug       string
	Issuer     string
	JWKSURI    string
	Mode       string
	PublicKeys []RemoteAppKey
	Audiences  []string
	// AllowedOrigins is the exact browser Origin allow-list for delegated
	// browser requests signed by this issuer.
	AllowedOrigins []string
	Role           string
	Enabled        *bool
}

OrgProvisionIssuer declares one remote_application (federation principal, #74) to register and bind as a member of the org. Slug defaults to the org slug when empty.

type OrgProvisionMembership added in v0.30.0

type OrgProvisionMembership struct {
	UserID string
	Role   string
}

OrgProvisionMembership declares one org membership and role.

type OrgProvisionRequest added in v0.30.0

type OrgProvisionRequest struct {
	Slug        string
	Issuers     []OrgProvisionIssuer
	Roles       []OrgProvisionRole
	Memberships []OrgProvisionMembership
	APIKeys     []OrgProvisionAPIKey
}

OrgProvisionRequest is the privileged/bootstrap org provisioning API for embedded hosts. It is additive/upsert by design: omitted objects are left alone, never removed.

type OrgProvisionResult added in v0.30.0

type OrgProvisionResult struct {
	Org           Org
	Created       bool
	Issuers       int
	Roles         int
	Memberships   int
	APIKeysMinted int
	APIKeysKept   int
	MintedAPIKeys []MintedOrgProvisionAPIKey
}

OrgProvisionResult summarizes one additive provisioning operation.

type OrgProvisionRole added in v0.30.0

type OrgProvisionRole struct {
	Name        string
	Permissions []string
}

OrgProvisionRole declares or updates one org role.

type OwnerNamespaceLookup added in v0.8.0

type OwnerNamespaceLookup struct {
	RequestedSlug string
	CanonicalSlug string
	Status        OwnerNamespaceLookupStatus
	Claimable     bool
	Exists        bool
	EntityKind    string
	Renamed       bool
	HoldUntil     *time.Time
	User          *OwnerNamespaceLookupUser
	Org           *OwnerNamespaceLookupOrg
}

type OwnerNamespaceLookupOrg added in v0.8.0

type OwnerNamespaceLookupOrg struct {
	ID          string
	Slug        string
	IsPersonal  bool
	OwnerUserID string
	State       OwnerNamespaceState
}

type OwnerNamespaceLookupStatus added in v0.8.0

type OwnerNamespaceLookupStatus string
const (
	OwnerNamespaceStatusRegisteredUser         OwnerNamespaceLookupStatus = "registered_user"
	OwnerNamespaceStatusRegisteredOrg          OwnerNamespaceLookupStatus = "registered_org"
	OwnerNamespaceStatusParkedUser             OwnerNamespaceLookupStatus = "parked_user"
	OwnerNamespaceStatusParkedOrg              OwnerNamespaceLookupStatus = "parked_org"
	OwnerNamespaceStatusRestrictedName         OwnerNamespaceLookupStatus = "restricted_name"
	OwnerNamespaceStatusRenamedUser            OwnerNamespaceLookupStatus = "renamed_user"
	OwnerNamespaceStatusRenamedOrg             OwnerNamespaceLookupStatus = "renamed_org"
	OwnerNamespaceStatusHeldByDeletedUser      OwnerNamespaceLookupStatus = "held_by_deleted_user"
	OwnerNamespaceStatusHeldByDeletedOrg       OwnerNamespaceLookupStatus = "held_by_deleted_org"
	OwnerNamespaceStatusHeldByRecentUserRename OwnerNamespaceLookupStatus = "held_by_recent_user_rename"
	OwnerNamespaceStatusHeldByRecentOrgRename  OwnerNamespaceLookupStatus = "held_by_recent_org_rename"
	OwnerNamespaceStatusUnregistered           OwnerNamespaceLookupStatus = "unregistered"
)

type OwnerNamespaceLookupUser added in v0.8.0

type OwnerNamespaceLookupUser struct {
	ID       string
	Username string
}

type OwnerNamespaceState added in v0.5.3

type OwnerNamespaceState string
const (
	OwnerNamespaceStateRestrictedName OwnerNamespaceState = "restricted_name"
	OwnerNamespaceStateParkedOrg      OwnerNamespaceState = "parked_org"
	OwnerNamespaceStateRegistered     OwnerNamespaceState = "registered_org"
)

type PendingChangeKind added in v0.15.5

type PendingChangeKind string

PendingChangeKind identifies one of the four verification-gated "deferred change" flows. They all share the same shape — "hold a change until an emailed/texted code is verified, then finalize it" — so they share one record type, one ephemeral storage namespace, and one set of generic operations, differing only in their per-kind finalizer.

const (
	KindRegisterEmail PendingChangeKind = "register_email"
	KindRegisterPhone PendingChangeKind = "register_phone"
	KindChangeEmail   PendingChangeKind = "change_email"
	KindChangePhone   PendingChangeKind = "change_phone"
)

type PendingRegistration

type PendingRegistration struct {
	Email           string
	Username        string
	PasswordHash    string
	PreferredLocale string
}

PendingRegistration represents an unverified registration

type PermissionDef added in v0.11.3

type PermissionDef struct {
	Name        string `json:"name"`
	Description string `json:"description,omitempty"`
}

PermissionDef is one entry in the permission set: an opaque permission string plus a human-readable description (surfaced to admin UIs).

func BasePermissions added in v0.11.3

func BasePermissions() []PermissionDef

BasePermissions are the org-management permissions authkit defines for every embedding app (reserved `org:` namespace), granular CRUD per resource (#95).

func BasePlatformPermissions added in v0.42.0

func BasePlatformPermissions() []PermissionDef

BasePlatformPermissions is AuthKit's native `platform:` (Layer-2) catalog.

type PreferredLocale added in v0.14.0

type PreferredLocale struct {
	Locale    string
	Source    string
	UpdatedAt *time.Time
}

type RecoverOrgResult added in v0.42.0

type RecoverOrgResult struct {
	APIKeysRevoked     int64  `json:"api_keys_revoked"`
	RemoteAppsDisabled int64  `json:"remote_apps_disabled"`
	MembersDemoted     int64  `json:"members_demoted"`
	NewOwnerUserID     string `json:"new_owner_user_id"`
}

RecoverOrgResult reports what the anti-takeover reset changed.

type RegistrationMode added in v0.12.4

type RegistrationMode string
const (
	RegistrationModeOpen               RegistrationMode = "open"
	RegistrationModeInviteOnly         RegistrationMode = "invite_only"
	RegistrationModeAdminOnly          RegistrationMode = "admin_only"
	RegistrationModeAdminBootstrapOnly RegistrationMode = "admin_bootstrap_only"
	RegistrationModeManifestOnly       RegistrationMode = "manifest_only"
	RegistrationModeClosed             RegistrationMode = "closed"
)

type RegistrationVerificationPolicy added in v0.5.0

type RegistrationVerificationPolicy string
const (
	RegistrationVerificationNone     RegistrationVerificationPolicy = "none"
	RegistrationVerificationOptional RegistrationVerificationPolicy = "optional"
	RegistrationVerificationRequired RegistrationVerificationPolicy = "required"
)

type RemoteAppAttributeDef added in v0.27.0

type RemoteAppAttributeDef struct {
	RemoteApplicationID string
	Key                 string
	Version             int32
	Definition          json.RawMessage
}

RemoteAppAttributeDef is one REFERENCE-mode attribute definition (#75): a remote_application registers (key, version) -> definition, and a platform resolves a token's `attributes.<key>: "<ref>"` reference back to it. The Definition is an OPAQUE JSON doc — AuthKit stores and serves it but NEVER interprets its semantics (same agnosticism as the token attributes bag).

type RemoteAppKey added in v0.27.0

type RemoteAppKey struct {
	KID          string `json:"kid,omitempty" yaml:"kid,omitempty"`
	PublicKeyPEM string `json:"public_key_pem" yaml:"public_key_pem"`
}

RemoteAppKey is one entry of a static-mode principal's human-managed key list (stored as jsonb; edited like an authorized_keys file).

type RemoteApplication added in v0.27.0

type RemoteApplication struct {
	ID      string
	Slug    string
	OrgID   string // optional controlling org; empty means bootstrap/operator-managed
	Issuer  string // OIDC iss
	JWKSURI string // OIDC jwks_uri (jwks mode only)
	// Mode is the trust source: RemoteAppModeJWKS (fetch from JWKSURI) XOR
	// RemoteAppModeStatic (human-managed PublicKeys list). Never both.
	Mode string
	// PublicKeys is the static-mode key list (empty in jwks mode).
	PublicKeys     []RemoteAppKey
	Audiences      []string
	AllowedOrigins []string
	Enabled        bool
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

RemoteApplication is a federation principal: an external system that authenticates by signing JWTs verified against its JWKS/public keys. It is optionally owned by an org and may hold org memberships with roles via the same polymorphic membership machinery as users (#74).

type RemoteApplicationAccessParams added in v0.28.0

type RemoteApplicationAccessParams struct {
	// Issuer becomes the `iss` claim: the remote_application's OIDC issuer,
	// registered with the validating resource server. Required when minting via
	// the free function; the *Service mint method defaults it to the Service's
	// configured Issuer when empty.
	Issuer string
	// Audiences becomes the `aud` claim: the target resource API(s).
	Audiences []string
	// TTL is the token lifetime. Defaults to 15m when zero.
	TTL time.Duration
	// JTI, when set, becomes the `jti` claim. Optional.
	JTI string
	// NotBefore, when set, becomes the `nbf` claim. Optional.
	NotBefore time.Time
	// Permissions, when non-nil, becomes the `permissions` claim: a DOWN-SCOPING
	// request for least-privilege (#76 amendment). The stored grant is the
	// ceiling; effective = this claim, but EVERY claimed perm must be within the
	// stored grant — an out-of-grant claimed perm REJECTS the token at verify (a
	// remote application access token can never widen). nil/absent => no claim
	// => full stored ceiling (backward-compatible with v0.28.0 tokens).
	Permissions []string
}

RemoteApplicationAccessParams describes a remote application access token to mint (#76): a remote_application signs a short-lived JWT that authenticates it AS ITSELF. The principal's authority is the STORED set AuthKit assigned it (org role membership only, #95), resolved at verify from the validated `iss`. The token therefore carries NO authority role claims of its own — and even if a caller adds them, the verifier ignores them.

type ResolvedAPIKey added in v0.41.0

type ResolvedAPIKey struct {
	APIKeyID string
	KeyID    string
	// OrgID is the immutable org uuid — the canonical identifier for
	// persistence and cross-service references. OrgSlug is the mutable
	// human-readable name, for presentation/logging only.
	OrgID       string
	OrgSlug     string
	Permissions []string
	Resources   []APIKeyResource
}

ResolvedAPIKey is the resource-aware API-key resolution result.

type ResourceScopeAuthorizationRequest added in v0.12.4

type ResourceScopeAuthorizationRequest struct {
	OrgSlug     string
	ActorUserID string
	Permissions []string
	Resources   []APIKeyResource
}

ResourceScopeAuthorizationRequest is passed to a host callback when the HTTP API-key mint route receives resource scopes. AuthKit has already validated shape and permission no-escalation before this hook runs.

type ResourceScopeAuthorizer added in v0.12.4

type ResourceScopeAuthorizer func(ctx context.Context, req ResourceScopeAuthorizationRequest) error

ResourceScopeAuthorizer is an optional host callback for API-key resource-scope no-escalation. Return an error to deny minting. AuthKit treats resource kinds and IDs as opaque and never interprets their semantics itself.

type SMSHealthChecker added in v0.15.4

type SMSHealthChecker interface {
	CheckHealth(ctx context.Context) error
}

SMSHealthChecker is an optional capability for SMS senders that can verify, without sending a message, that they are configured to actually deliver (valid credentials, an attached sender, and a verified/registered number). CheckHealth returns nil when delivery is expected to succeed, or a descriptive error explaining why it will not (e.g. an unverified toll-free sender that would otherwise fail silently with Twilio error 30032).

type SMSSender

type SMSSender interface {
	SendVerification(ctx context.Context, phone string, msg VerificationMessage) error
	SendPasswordResetLink(ctx context.Context, phone, token string) error
	SendLoginCode(ctx context.Context, phone, code string) error
}

SMSSender sends verification/login/reset SMS messages.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service is the core auth service used by HTTP adapters.

func NewFromConfig

func NewFromConfig(cfg Config) (*Service, error)

NewFromConfig creates a Service from high-level Config + Stores. If Keys is nil, auto-discovers keys from environment variables, filesystem, or generates development keys.

func NewService

func NewService(opts Options, keys Keyset) *Service

func (*Service) AcceptOrgInvite added in v0.4.6

func (s *Service) AcceptOrgInvite(ctx context.Context, inviteID, userID string) error

func (*Service) AddMember added in v0.4.4

func (s *Service) AddMember(ctx context.Context, orgSlug, userID string) error

func (*Service) AddRemoteApplicationMember added in v0.27.0

func (s *Service) AddRemoteApplicationMember(ctx context.Context, orgSlug, appID, role string) error

AddRemoteApplicationMember makes a remote_application a member of a org with the given role, via the SAME polymorphic org_memberships machinery as users. role defaults to 'member'; the role must be defined on the org (or a materializable default). appID is the remote_application uuid.

func (*Service) AdminCountUsers added in v0.40.0

func (s *Service) AdminCountUsers(ctx context.Context, opts AdminUserListOptions) (int64, error)

AdminCountUsers returns the number of users matching opts (same filters as AdminListUsers, ignoring pagination/sort).

func (*Service) AdminDeleteUser

func (s *Service) AdminDeleteUser(ctx context.Context, id string) error

func (*Service) AdminGetUser

func (s *Service) AdminGetUser(ctx context.Context, id string) (*AdminUser, error)

func (*Service) AdminListOrgs added in v0.42.0

func (s *Service) AdminListOrgs(ctx context.Context, search string, includeDeleted bool, limit, offset int32) ([]OrgAdminSummary, error)

AdminListOrgs lists orgs for the platform directory (paginated, optional slug search, optional inclusion of soft-deleted).

func (*Service) AdminListUserSessions

func (s *Service) AdminListUserSessions(ctx context.Context, userID string) ([]Session, error)

Helper exposed for admin endpoints

func (*Service) AdminListUsers

func (s *Service) AdminListUsers(ctx context.Context, opts AdminUserListOptions) (*AdminListUsersResult, error)

AdminListUsers is the generic admin user-directory list (issue #91): generic role/org/status filter + search + sort + offset pagination, with optional provider-backed entitlement filtering. Each row is enriched with role slugs and (via the entitlements provider) entitlement names.

func (*Service) AdminOrgDetail added in v0.42.0

func (s *Service) AdminOrgDetail(ctx context.Context, orgID string) (*OrgAdminDetail, error)

AdminOrgDetail returns the entity view of one org (by id), including its active member count. Internals (the member list itself) are NOT exposed.

func (*Service) AdminRevokeUserSessions

func (s *Service) AdminRevokeUserSessions(ctx context.Context, userID string) error

func (*Service) AdminSetPassword

func (s *Service) AdminSetPassword(ctx context.Context, userID, new string) error

AdminSetPassword force-sets a user's password (admin only, no current password required)

func (*Service) AssignPlatformRole added in v0.42.0

func (s *Service) AssignPlatformRole(ctx context.Context, userID, role string) error

AssignPlatformRole grants a user a platform role (idempotent) — this is what mints a platform-admin. The role must exist.

func (*Service) AssignRole added in v0.4.4

func (s *Service) AssignRole(ctx context.Context, orgSlug, userID, role string) error

func (*Service) AssignRoleBySlug

func (s *Service) AssignRoleBySlug(ctx context.Context, userID, slug string) error

Exported wrappers for admin endpoints

func (*Service) AuthorizeAPIKeyResources added in v0.41.0

func (s *Service) AuthorizeAPIKeyResources(ctx context.Context, req ResourceScopeAuthorizationRequest) error

func (*Service) BanUser

func (s *Service) BanUser(ctx context.Context, userID string, reason *string, until *time.Time, bannedBy string) error

BanUser disables a user account and stores ban metadata.

func (*Service) BeginPasswordReset added in v0.5.0

func (s *Service) BeginPasswordReset(ctx context.Context, token string, sessionTTL time.Duration) (string, error)

BeginPasswordReset validates and consumes a password reset token, then issues a short-lived one-time reset session for browser handoff.

func (*Service) CancelEmailChange added in v0.15.5

func (s *Service) CancelEmailChange(ctx context.Context, userID string) error

CancelEmailChange aborts a pending email-change for the user, clearing the unified pending-change record. The new email is applied only on confirmation, so there is nothing to roll back. Idempotent: a no-op when none is pending.

func (*Service) CancelPhoneChange added in v0.15.5

func (s *Service) CancelPhoneChange(ctx context.Context, userID, phone string) error

CancelPhoneChange aborts a pending phone-change for the user, clearing the unified pending-change record. Because the new phone is held only in the pending record and never optimistically applied to the profile, there is nothing to roll back. Idempotent: a no-op when no pending change exists.

func (*Service) ChangePassword

func (s *Service) ChangePassword(ctx context.Context, userID, current, new string, keepSessionID *string) error

ChangePassword sets or changes a user's password. If the user already has a password, current must verify; otherwise current is ignored. Always Argon2id-hashes the new password and upserts it, then revokes all other sessions for the user; caller may keep one active session via keepSessionID.

func (*Service) CheckPendingRegistrationConflict

func (s *Service) CheckPendingRegistrationConflict(ctx context.Context, email, username string) (bool, bool, error)

CheckPendingRegistrationConflict checks if email or username exists in users or pending registration cache. Returns (emailTaken, usernameTaken, error)

func (*Service) CheckPhoneRegistrationConflict

func (s *Service) CheckPhoneRegistrationConflict(ctx context.Context, phone, username string) (bool, bool, error)

CheckPhoneRegistrationConflict checks if phone or username exists in users OR pending tables. Returns (phoneTaken, usernameTaken, error)

func (*Service) CheckSMSHealth added in v0.15.4

func (s *Service) CheckSMSHealth(ctx context.Context) error

CheckSMSHealth probes whether the configured SMS sender can actually deliver, without sending a message, when the sender implements SMSHealthChecker. The result is cached and gates phone-based flows via SMSAvailable. It returns the probe error (nil = healthy) so callers can log it. When no sender is configured or the sender cannot self-check, it records healthy=true (delivery readiness is then governed solely by sender presence, as before).

func (*Service) CheckUserPassword added in v0.24.0

func (s *Service) CheckUserPassword(ctx context.Context, userID, pass string) error

CheckUserPassword is the error-returning form of VerifyUserPassword: nil on success, ErrPasswordResetRequired when the stored hash is flagged HashAlgoLegacyResetRequired (no plaintext can verify; the user must reset), and a generic unauthorized error otherwise. Callers that need to route reset-required users (reauth, change-password) should use this form.

func (*Service) ClaimOrgNamespace added in v0.5.3

func (s *Service) ClaimOrgNamespace(ctx context.Context, slug, ownerUserID string) (orgID string, created bool, err error)

ClaimOrgNamespace claims org ownership for a specific existing user.

Rules:

  • parked_org -> registered_org + owner membership assignment
  • already-registered orgs return ErrOwnerNamespaceAlreadyClaimed
  • restricted_name (or missing namespace) creates the org if needed, then claims it
  • owner user must exist and not be soft-deleted

func (*Service) ClaimUserNamespace added in v0.6.0

func (s *Service) ClaimUserNamespace(ctx context.Context, slug string) (userID, orgID string, created bool, err error)

ClaimUserNamespace ensures a slug resolves to a non-reserved user namespace.

Behavior:

  • If no same-slug user exists, creates one (and a personal org) and marks it claimed.
  • Clears user reserved metadata and any restricted-name marker for the slug.
  • Forces the user's personal org namespace state to registered_org when present.
  • If a same-slug non-personal org exists, returns ErrInvalidOwnerNamespaceTransition.

func (*Service) CleanupExpiredAuthState added in v0.9.0

func (s *Service) CleanupExpiredAuthState(ctx context.Context) error

CleanupExpiredAuthState removes expired transient AuthKit state that lives in postgres. Short-lived verification state — pending registrations, pending email/phone changes, email/phone verifications, and password resets — now lives entirely in the ephemeral store (Redis when multi-instance, in-memory otherwise) and expires automatically by TTL, so no database sweep is needed for it. The only persistent auth state requiring a sweep is revoked/expired refresh sessions.

func (*Service) Clear2FAChallenge

func (s *Service) Clear2FAChallenge(ctx context.Context, userID string) error

Clear2FAChallenge removes the stored challenge after successful 2FA verification.

func (*Service) ConfirmEmailChange

func (s *Service) ConfirmEmailChange(ctx context.Context, userID, code string) error

ConfirmEmailChange verifies the code and updates the user's email address. This is called when the user enters the verification code sent to their new email.

func (*Service) ConfirmEmailVerification

func (s *Service) ConfirmEmailVerification(ctx context.Context, token string) (userID string, err error)

ConfirmEmailVerification verifies a token and marks email_verified = true. Returns the userID of the verified user.

func (*Service) ConfirmPasswordReset

func (s *Service) ConfirmPasswordReset(ctx context.Context, token, newPassword string) (string, error)

ConfirmPasswordReset verifies token and sets a new password.

func (*Service) ConfirmPasswordResetWithSession added in v0.5.0

func (s *Service) ConfirmPasswordResetWithSession(ctx context.Context, resetSession, newPassword string) (string, error)

ConfirmPasswordResetWithSession consumes a reset session and sets the new password.

func (*Service) ConfirmPendingPhoneRegistration

func (s *Service) ConfirmPendingPhoneRegistration(ctx context.Context, phone, code string) (userID string, err error)

ConfirmPendingPhoneRegistration verifies code and creates the actual user account. Implements "first to verify wins" - whoever verifies first gets the username/phone.

func (*Service) ConfirmPendingPhoneRegistrationByToken added in v0.5.0

func (s *Service) ConfirmPendingPhoneRegistrationByToken(ctx context.Context, token string) (string, error)

ConfirmPendingPhoneRegistrationByToken verifies a pending phone registration using either a manual code or a high-entropy link token.

func (*Service) ConfirmPendingRegistration

func (s *Service) ConfirmPendingRegistration(ctx context.Context, token string) (userID string, err error)

ConfirmPendingRegistration verifies token and creates the actual user account. This implements "first to verify wins" - whoever verifies first gets the username/email.

func (*Service) ConfirmPhoneChange

func (s *Service) ConfirmPhoneChange(ctx context.Context, userID, phone, code string) error

ConfirmPhoneChange verifies the code and updates the user's phone number. This is called when the user enters the verification code sent to their new phone.

func (*Service) ConfirmPhoneVerification

func (s *Service) ConfirmPhoneVerification(ctx context.Context, phone, code string) error

ConfirmPhoneVerification verifies a token and marks phone_verified = true.

func (*Service) ConfirmPhoneVerificationByToken added in v0.5.0

func (s *Service) ConfirmPhoneVerificationByToken(ctx context.Context, token string) error

ConfirmPhoneVerificationByToken verifies phone ownership using a one-click token.

func (*Service) ConfirmPhoneVerificationByTokenUserID added in v0.8.1

func (s *Service) ConfirmPhoneVerificationByTokenUserID(ctx context.Context, token string) (string, error)

ConfirmPhoneVerificationByTokenUserID verifies phone ownership using a one-click token and returns the user ID.

func (*Service) ConfirmPhoneVerificationUserID added in v0.8.1

func (s *Service) ConfirmPhoneVerificationUserID(ctx context.Context, phone, code string) (string, error)

ConfirmPhoneVerificationUserID verifies a token, marks phone_verified = true, and returns the user ID.

func (s *Service) CountProviderLinks(ctx context.Context, userID string) int

Public wrappers

func (*Service) Create2FAChallenge

func (s *Service) Create2FAChallenge(ctx context.Context, userID string) (string, error)

Create2FAChallenge creates a short-lived challenge to prove password verification before 2FA.

func (*Service) CreateOrg added in v0.4.4

func (s *Service) CreateOrg(ctx context.Context, slug string) (*Org, error)

CreateOrg creates an ownerless org for privileged bootstrap/admin callers. Public self-service org registration must use CreateOrgForUser so the org, owner membership, and owner role are created atomically.

func (*Service) CreateOrgForUser added in v0.30.0

func (s *Service) CreateOrgForUser(ctx context.Context, req CreateOrgForUserRequest) (*Org, error)

CreateOrgForUser transactionally creates a org and assigns the registering user as its sole initial owner. This is the core API behind public POST /orgs.

func (*Service) CreateOrgInvite added in v0.4.6

func (s *Service) CreateOrgInvite(ctx context.Context, orgSlug, userID, invitedBy, role string, expiresAt *time.Time) (*OrgInvite, error)

func (*Service) CreatePendingPhoneRegistration

func (s *Service) CreatePendingPhoneRegistration(ctx context.Context, phone, username, passwordHash string) (string, error)

CreatePendingPhoneRegistration creates a pending phone registration and sends SMS verification code. Returns 6-digit code for verification. Code expires in 10 minutes (shorter than email).

func (*Service) CreatePendingPhoneRegistrationWithLocale added in v0.14.0

func (s *Service) CreatePendingPhoneRegistrationWithLocale(ctx context.Context, phone, username, passwordHash, preferredLocale string) (string, error)

func (*Service) CreatePendingRegistration

func (s *Service) CreatePendingRegistration(ctx context.Context, email, username, passwordHash string, ttl time.Duration) (string, error)

CreatePendingRegistration creates a pending registration and sends verification email. Returns token for verification. Allows duplicate pending registrations (last one wins).

func (*Service) CreatePendingRegistrationWithLocale added in v0.14.0

func (s *Service) CreatePendingRegistrationWithLocale(ctx context.Context, email, username, passwordHash string, ttl time.Duration, preferredLocale string) (string, error)

func (*Service) CreateUser

func (s *Service) CreateUser(ctx context.Context, email, username string) (*User, error)

func (*Service) DeclineOrgInvite added in v0.4.6

func (s *Service) DeclineOrgInvite(ctx context.Context, inviteID, userID string) error

func (*Service) DefinePlatformRole added in v0.42.0

func (s *Service) DefinePlatformRole(ctx context.Context, role string) error

DefinePlatformRole creates a platform role name (idempotent).

func (*Service) DefineRole added in v0.4.4

func (s *Service) DefineRole(ctx context.Context, orgSlug, role string) error

func (*Service) DeletePendingPhoneRegistrationByPhone added in v0.15.4

func (s *Service) DeletePendingPhoneRegistrationByPhone(ctx context.Context, phone string) error

DeletePendingPhoneRegistrationByPhone removes a pending phone registration (and all its verification tokens) for the given phone, if one exists. No-op when none exists.

func (*Service) DeletePendingRegistrationByEmail added in v0.15.4

func (s *Service) DeletePendingRegistrationByEmail(ctx context.Context, email string) error

DeletePendingRegistrationByEmail removes a pending email registration (and all its verification tokens) for the given email, if one exists. Used to abandon a pending registration the user explicitly cancelled. No-op when none exists.

func (*Service) DeletePlatformRole added in v0.42.0

func (s *Service) DeletePlatformRole(ctx context.Context, role string) (int64, error)

DeletePlatformRole removes a platform role (and, by cascade, its perms and every assignment of it). Returns the number of role rows removed.

func (*Service) DeleteRemoteAppAttributeDef added in v0.27.0

func (s *Service) DeleteRemoteAppAttributeDef(ctx context.Context, appID, key string) error

DeleteRemoteAppAttributeDef removes ALL versions of a key for the remote_application. Returns ErrAttributeDefNotFound when nothing matched.

func (*Service) DeleteRemoteApplication added in v0.27.0

func (s *Service) DeleteRemoteApplication(ctx context.Context, issuer string) error

DeleteRemoteApplication removes a remote_application by OIDC issuer URL.

func (*Service) DeleteRole added in v0.4.4

func (s *Service) DeleteRole(ctx context.Context, orgSlug, role string) error

func (*Service) DeriveUsername

func (s *Service) DeriveUsername(email string) string

func (*Service) DeriveUsernameForOAuth

func (s *Service) DeriveUsernameForOAuth(ctx context.Context, provider, preferred, email, displayName string) string

DeriveUsernameForOAuth prefers provider-preferred usernames; falls back to email local part or display name.

func (*Service) Disable2FA

func (s *Service) Disable2FA(ctx context.Context, userID string) error

Disable2FA disables two-factor authentication for a user

func (*Service) EffectivePermissions added in v0.11.3

func (s *Service) EffectivePermissions(ctx context.Context, orgSlug, userID string) ([]string, error)

EffectivePermissions returns the union of permissions across all of the user's roles in the org, expanded against the catalog. This is the single source of truth for "what can this principal do" (the embedding app calls it at request time for enforcement — do NOT bake into the JWT).

func (*Service) EffectivePlatformPermissions added in v0.42.0

func (s *Service) EffectivePlatformPermissions(ctx context.Context, userID string) ([]string, error)

EffectivePlatformPermissions returns the union of a user's platform permissions across all their platform roles, expanded against the platform catalog (globs expand; literals pass through). ONE indexed JOIN + in-memory expansion; a regular user (no platform roles) gets an empty set.

func (*Service) EffectiveRolePermissions added in v0.11.3

func (s *Service) EffectiveRolePermissions(ctx context.Context, orgSlug, role string) ([]string, error)

EffectiveRolePermissions returns a single role's permissions expanded against the catalog (globs included). Used to enforce no-escalation when assigning a role to a member (the assigner must hold everything the role grants).

func (*Service) Enable2FA

func (s *Service) Enable2FA(ctx context.Context, userID, method string, phoneNumber *string) ([]string, error)

Enable2FA enables two-factor authentication for a user and generates backup codes. Returns the plaintext backup codes (caller must show these to user ONCE).

func (*Service) EnsurePlatformSuperAdmin added in v0.42.0

func (s *Service) EnsurePlatformSuperAdmin(ctx context.Context, userID string) error

EnsurePlatformSuperAdmin is the bootstrap escape-hatch for minting the FIRST platform-admin out-of-band (like an org's first `owner` — you can't grant a platform role through the platform API until someone holds one). It seeds the `super-admin` role (granting `platform:*`) and assigns it to userID. Idempotent; intended for a host's bootstrap/manifest, never a public route.

func (*Service) EntitlementsProvider

func (s *Service) EntitlementsProvider() EntitlementsProvider

func (*Service) EphemeralMode

func (s *Service) EphemeralMode() EphemeralMode

func (*Service) ExchangeRefreshToken

func (s *Service) ExchangeRefreshToken(ctx context.Context, refreshToken string, ua string, ip net.IP) (idToken string, expiresAt time.Time, newRefresh string, err error)

ExchangeRefreshToken rotates a refresh token and returns a new ID token + refresh token.

func (*Service) GenerateAvailableUsername

func (s *Service) GenerateAvailableUsername(ctx context.Context, base string) string

GenerateAvailableUsername tries base, then minimal numeric suffixes, then a short fallback.

func (*Service) GenerateSIWSChallenge

func (s *Service) GenerateSIWSChallenge(ctx context.Context, cache siws.ChallengeCache, domain, address, username string) (siws.SignInInput, error)

GenerateSIWSChallenge creates a new SIWS challenge for the given address. The challenge is stored in the cache and must be verified within 15 minutes.

func (*Service) Get2FASettings

func (s *Service) Get2FASettings(ctx context.Context, userID string) (*TwoFactorSettings, error)

Get2FASettings retrieves a user's 2FA settings

func (*Service) GetDiscordUsername

func (s *Service) GetDiscordUsername(ctx context.Context, userID string) (string, error)

Convenience: Discord username

func (*Service) GetEmailByUserID

func (s *Service) GetEmailByUserID(ctx context.Context, id string) (string, error)

func (*Service) GetOrgMetadata added in v0.4.8

func (s *Service) GetOrgMetadata(ctx context.Context, orgID string) (map[string]any, error)

func (*Service) GetOrgNamespaceState added in v0.5.3

func (s *Service) GetOrgNamespaceState(ctx context.Context, orgID string) (OwnerNamespaceState, error)

func (*Service) GetOwnerNamespaceStateBySlug added in v0.5.3

func (s *Service) GetOwnerNamespaceStateBySlug(ctx context.Context, slug string) (OwnerNamespaceState, error)

func (*Service) GetPendingEmailChange

func (s *Service) GetPendingEmailChange(ctx context.Context, userID string) (string, error)

GetPendingEmailChange retrieves the pending email change for a user, if any. A unified change_email record exists only for an actual change (verifying the current address uses a separate store), so its presence already means "change".

func (*Service) GetPendingPhoneRegistrationByPhone

func (s *Service) GetPendingPhoneRegistrationByPhone(ctx context.Context, phone string) (*PendingRegistration, error)

GetPendingPhoneRegistrationByPhone looks up a pending phone registration by phone number. (PendingRegistration.Email carries the phone for phone registrations, preserving prior behavior.)

func (*Service) GetPendingRegistrationByEmail

func (s *Service) GetPendingRegistrationByEmail(ctx context.Context, email string) (*PendingRegistration, error)

GetPendingRegistrationByEmail looks up a pending registration by email.

func (*Service) GetPersonalOrgForUser added in v0.4.6

func (s *Service) GetPersonalOrgForUser(ctx context.Context, userID string) (*Org, error)

func (*Service) GetPlatformRolePermissions added in v0.42.0

func (s *Service) GetPlatformRolePermissions(ctx context.Context, role string) ([]string, error)

GetPlatformRolePermissions returns a platform role's RAW grant tokens.

func (*Service) GetPreferredLocale added in v0.14.0

func (s *Service) GetPreferredLocale(ctx context.Context, userID string) (PreferredLocale, error)
func (s *Service) GetProviderLink(ctx context.Context, providerSlug, subject string) (string, *string, error)

Additional public helpers used by OIDC flow

func (*Service) GetProviderLinkByIssuer

func (s *Service) GetProviderLinkByIssuer(ctx context.Context, issuer, subject string) (string, *string, error)

Issuer-based provider link helpers (preferred)

func (*Service) GetProviderUsername

func (s *Service) GetProviderUsername(ctx context.Context, userID, provider string) (string, error)

func (*Service) GetRemoteApplication added in v0.27.0

func (s *Service) GetRemoteApplication(ctx context.Context, issuer string) (*RemoteApplication, error)

GetRemoteApplication returns a remote_application by OIDC issuer URL.

func (*Service) GetRemoteApplicationBySlug added in v0.27.0

func (s *Service) GetRemoteApplicationBySlug(ctx context.Context, slug string) (*RemoteApplication, error)

GetRemoteApplicationBySlug returns a remote_application by slug.

func (*Service) GetRolePermissions added in v0.11.3

func (s *Service) GetRolePermissions(ctx context.Context, orgSlug, role string) ([]string, error)

GetRolePermissions returns a role's RAW permission tokens (literals and namespace-anchored globs such as `org:*`).

func (*Service) GetSolanaAddress

func (s *Service) GetSolanaAddress(ctx context.Context, userID string) (string, error)

GetSolanaAddress retrieves the Solana wallet address linked to a user, if any.

func (*Service) GetSolanaLinkedAccount added in v0.15.0

func (s *Service) GetSolanaLinkedAccount(ctx context.Context, userID string) (*SolanaLinkedAccount, error)

GetSolanaLinkedAccount retrieves the SIWS-linked wallet and its AuthKit-owned metadata.

func (*Service) GetUserByEmail

func (s *Service) GetUserByEmail(ctx context.Context, email string) (*User, error)

func (*Service) GetUserByPhone

func (s *Service) GetUserByPhone(ctx context.Context, phone string) (*User, error)

GetUserByPhone looks up a user by phone number.

func (*Service) GetUserBySolanaAddress

func (s *Service) GetUserBySolanaAddress(ctx context.Context, address string) (*User, error)

GetUserBySolanaAddress looks up a user by their Solana wallet address.

func (*Service) GetUserByUsername

func (s *Service) GetUserByUsername(ctx context.Context, username string) (*User, error)

func (*Service) GetUserMetadata added in v0.4.8

func (s *Service) GetUserMetadata(ctx context.Context, userID string) (map[string]any, error)

func (*Service) HardDeleteUser

func (s *Service) HardDeleteUser(ctx context.Context, userID string) error

HardDeleteUser permanently deletes the user row and dependent AuthKit rows via ON DELETE CASCADE.

func (*Service) HasEmailSender

func (s *Service) HasEmailSender() bool

HasEmailSender returns true if an email sender is configured.

func (*Service) HasPassword

func (s *Service) HasPassword(ctx context.Context, userID string) bool

func (*Service) HasPermission added in v0.11.3

func (s *Service) HasPermission(ctx context.Context, orgSlug, userID, perm string) (bool, error)

HasPermission reports whether the user holds perm in the org.

func (*Service) HasPlatformPermission added in v0.42.0

func (s *Service) HasPlatformPermission(ctx context.Context, userID, perm string) (bool, error)

HasPlatformPermission reports whether the user holds perm in the platform layer.

func (*Service) HasSMSSender

func (s *Service) HasSMSSender() bool

HasSMSSender returns true if an SMS sender is configured.

func (*Service) HostDeleteUser

func (s *Service) HostDeleteUser(ctx context.Context, id string, soft bool) error

HostDeleteUser performs deletion on behalf of the host application. If soft is true, it performs a soft delete (see SoftDeleteUser). If false, it hard-deletes the user and all dependent rows via ON DELETE CASCADE.

func (*Service) ImportUser added in v0.9.0

func (s *Service) ImportUser(ctx context.Context, input ImportUserInput) (*User, error)

func (*Service) IsOrgMember added in v0.4.4

func (s *Service) IsOrgMember(ctx context.Context, orgSlug, userID string) (bool, error)

func (*Service) IsOrgReserved added in v0.4.8

func (s *Service) IsOrgReserved(ctx context.Context, orgID string) (bool, error)

func (*Service) IsUserAllowed

func (s *Service) IsUserAllowed(ctx context.Context, userID string) (bool, error)

func (*Service) IsUserReserved added in v0.5.3

func (s *Service) IsUserReserved(ctx context.Context, userID string) (bool, error)

func (*Service) IssueAccessToken

func (s *Service) IssueAccessToken(ctx context.Context, userID, email string, extra map[string]any) (token string, expiresAt time.Time, err error)

IssueAccessToken builds and signs an access token (JWT) for the given user. Includes core registered claims plus: - entitlements (authoritative short-lived snapshot) Extra claims in `extra` are merged into the token body (e.g., sid).

func (*Service) IssueRefreshSession

func (s *Service) IssueRefreshSession(ctx context.Context, userID, userAgent string, ip net.IP) (sessionID, refreshToken string, expiresAt *time.Time, err error)

IssueRefreshSession creates a session row and returns a new refresh token string.

func (*Service) JWKS

func (s *Service) JWKS() jwtkit.JWKS

JWKS returns a JWKS built from configured public keys.

func (*Service) Keyfunc

func (s *Service) Keyfunc() func(token *jwt.Token) (any, error)

Keyfunc looks up a public key by KID, falling back to the active key if missing.

func (*Service) LinkProvider

func (s *Service) LinkProvider(ctx context.Context, userID, provider, subject string, email *string) error

func (*Service) LinkProviderByIssuer

func (s *Service) LinkProviderByIssuer(ctx context.Context, userID, issuer, providerSlug, subject string, email *string) error

func (*Service) LinkSolanaWallet

func (s *Service) LinkSolanaWallet(ctx context.Context, cache siws.ChallengeCache, userID string, output siws.SignInOutput) error

LinkSolanaWallet links a Solana wallet to an existing user account.

func (*Service) ListAPIKeys added in v0.41.0

func (s *Service) ListAPIKeys(ctx context.Context, orgSlug string) ([]APIKey, error)

ListAPIKeys returns metadata for every API key of the org (including revoked/expired ones, so an admin can see and clean them up). The secret is never returned.

func (*Service) ListEntitlements

func (s *Service) ListEntitlements(ctx context.Context, userID string) []string

ListEntitlements returns current entitlement names for a user (fresh from the provider). A provider failure is logged and returned as none — callers (admin user views) degrade rather than fail.

func (*Service) ListOrgAliases added in v0.4.6

func (s *Service) ListOrgAliases(ctx context.Context, orgID string) ([]string, error)

ListOrgAliases returns every historical slug this org has held (excluding the current one). Source: `org_renames.from_slug` (issue #58). Distinct values.

func (*Service) ListOrgDefinedRoles added in v0.4.4

func (s *Service) ListOrgDefinedRoles(ctx context.Context, orgSlug string) ([]string, error)

func (*Service) ListOrgInvites added in v0.4.6

func (s *Service) ListOrgInvites(ctx context.Context, orgSlug, status string) ([]OrgInvite, error)

func (*Service) ListOrgMembers added in v0.4.4

func (s *Service) ListOrgMembers(ctx context.Context, orgSlug string) ([]string, error)

func (*Service) ListOrgMembershipsForUser added in v0.4.4

func (s *Service) ListOrgMembershipsForUser(ctx context.Context, userID string) ([]string, error)

func (*Service) ListPlatformRoles added in v0.42.0

func (s *Service) ListPlatformRoles(ctx context.Context) ([]string, error)

ListPlatformRoles returns every defined platform role name.

func (*Service) ListRemoteAppAttributeDefs added in v0.27.0

func (s *Service) ListRemoteAppAttributeDefs(ctx context.Context, appID string) ([]RemoteAppAttributeDef, error)

ListRemoteAppAttributeDefs returns all definitions a remote_application has registered (every key + version), newest version first within each key.

func (*Service) ListRemoteApplications added in v0.27.0

func (s *Service) ListRemoteApplications(ctx context.Context, activeOnly bool) ([]RemoteApplication, error)

ListRemoteApplications returns registered remote_applications. When activeOnly is true, only enabled rows are returned.

func (*Service) ListRoleSlugsByUser

func (s *Service) ListRoleSlugsByUser(ctx context.Context, userID string) []string

Public helpers for HTTP adapters

func (*Service) ListUserInvites added in v0.4.6

func (s *Service) ListUserInvites(ctx context.Context, userID, status string) ([]OrgInvite, error)

func (*Service) ListUserOrgMembershipsAndRoles added in v0.4.4

func (s *Service) ListUserOrgMembershipsAndRoles(ctx context.Context, userID string) ([]OrgMembership, error)

func (*Service) ListUserSessions

func (s *Service) ListUserSessions(ctx context.Context, userID string) ([]Session, error)

ListUserSessions lists active sessions for a user and issuer.

func (*Service) ListUserSlugAliases added in v0.4.6

func (s *Service) ListUserSlugAliases(ctx context.Context, userID string) ([]string, error)

ListUserSlugAliases returns every historical username this user has held (excluding the current one). Source: `user_renames.from_slug` (issue #58). Distinct values; order by usage timeline.

func (*Service) ListUsersDeletedBefore

func (s *Service) ListUsersDeletedBefore(ctx context.Context, cutoff time.Time, limit int) ([]string, error)

ListUsersDeletedBefore returns user IDs for users soft-deleted before the cutoff. It is intended for retention/purge workflows in the host application.

func (*Service) LogPasswordChanged added in v0.4.2

func (s *Service) LogPasswordChanged(ctx context.Context, userID string, sessionID string, ip *string, ua *string)

LogPasswordChanged records a password change event for a user (best-effort).

func (*Service) LogPasswordRecovery added in v0.4.2

func (s *Service) LogPasswordRecovery(ctx context.Context, userID string, method, sessionID string, ip *string, ua *string)

func (*Service) LogSessionCreated

func (s *Service) LogSessionCreated(ctx context.Context, userID string, method string, sessionID string, ip *string, ua *string)

LogSessionCreated records a session creation event via the configured AuthEventLogger (best-effort).

func (*Service) LogSessionFailed added in v0.4.2

func (s *Service) LogSessionFailed(ctx context.Context, userID string, sessionID string, reason *string, ip *string, ua *string)

func (*Service) LookupOwnerNamespace added in v0.8.0

func (s *Service) LookupOwnerNamespace(ctx context.Context, slug string) (*OwnerNamespaceLookup, error)

LookupOwnerNamespace returns one canonical availability/routing view for an owner slug. It intentionally uses the same sources as both owner resolution and owner-slug availability so callers can distinguish "not registered" from "not resolvable but still held".

func (*Service) MarkSessionAuthenticated added in v0.8.3

func (s *Service) MarkSessionAuthenticated(ctx context.Context, userID, sessionID string) error

func (*Service) MintAPIKey added in v0.41.0

func (s *Service) MintAPIKey(ctx context.Context, orgSlug, name string, permissions []string, createdBy string, expiresAt *time.Time) (APIKey, string, error)

MintAPIKey inserts a new API key for the org and returns its metadata plus the full plaintext token (shown ONCE). permissions must already be authorized by the caller (the grant decision lives in the HTTP handler / host hook). expiresAt is optional (nil = no expiry) and is capped to APIKeyMaxTTL when set.

func (*Service) MintAPIKeyWithOptions added in v0.41.0

func (s *Service) MintAPIKeyWithOptions(ctx context.Context, orgSlug string, opts APIKeyMintOptions) (APIKey, string, error)

MintAPIKeyWithOptions inserts a new API key using the resource-aware mint contract. Permissions and resources must already be authorized by the caller.

func (*Service) MintCustomJWT added in v0.26.0

func (s *Service) MintCustomJWT(ctx context.Context, opts CustomJWTMintOptions) (string, error)

MintCustomJWT signs a JWT carrying an arbitrary first-party claim set using the Service's internal signer — the SAME signing path as MintServiceJWT / MintDelegatedAccessToken. The host passes a claim map (+ a few controlled headers) and NEVER touches the private key, the PEM, or a raw signer; the #70 hard boundary holds.

AuthKit sets the `kid`/`alg` JOSE headers (via the signer) and the registered `iss`/`iat`/`exp` claims; everything else comes from the host. See CustomJWTMintOptions for the claim-precedence rules. The host Claims map may not set `iss`/`iat`/`exp` (ErrCustomClaimsReserved).

func (*Service) MintDelegatedAccessToken added in v0.26.0

func (s *Service) MintDelegatedAccessToken(ctx context.Context, p DelegatedAccessParams) (string, error)

MintDelegatedAccessToken signs a canonical delegated access token using the Service's internal signer. The host passes claims/params only and NEVER touches the private key. When p.Issuer is empty it defaults to the Service's configured Issuer. See the package-level MintDelegatedAccessToken for the claim contract.

func (*Service) MintRemoteApplicationAccessToken added in v0.28.0

func (s *Service) MintRemoteApplicationAccessToken(ctx context.Context, p RemoteApplicationAccessParams) (string, error)

MintRemoteApplicationAccessToken signs a remote application access token using the Service's internal signer. When p.Issuer is empty it defaults to the Service's configured Issuer.

func (*Service) MintServiceJWT added in v0.13.1

func (s *Service) MintServiceJWT(ctx context.Context, opts ServiceJWTMintOptions) (string, ServiceJWTClaims, error)

MintServiceJWT creates a short-lived signed service JWT from AuthKit's active signing key. It defaults to a 15-minute lifetime and stamps `token_use=service`; it does not grant host permissions by itself.

func (*Service) Options

func (s *Service) Options() Options

Options exposes immutable configuration for callers that need to validate claims.

func (*Service) ParkOrgNamespace added in v0.6.1

func (s *Service) ParkOrgNamespace(ctx context.Context, slug string) (orgID string, created bool, err error)

ParkOrgNamespace parks `slug` as a parked_org. Works whether or not the slug is currently in owner_reserved_names — any caller-supplied slug is parkable, even bootstrap-reserved names like 'root' or 'admin'. If a reserved-name row exists it's deleted as part of the transaction. Internal-library API only — not exposed publicly.

func (*Service) ParkUserNamespace added in v0.6.0

func (s *Service) ParkUserNamespace(ctx context.Context, slug string) (userID, orgID string, created bool, err error)

ParkUserNamespace ensures a slug is represented as a parked user namespace.

Behavior:

  • If no same-slug user exists, creates a placeholder user (and personal org), then parks it.
  • If a same-slug non-personal org exists, returns ErrInvalidOwnerNamespaceTransition.
  • Requires the slug to be valid and available for user ownership semantics.

func (*Service) PasswordLogin

func (s *Service) PasswordLogin(ctx context.Context, email, pass string, extra map[string]any) (string, time.Time, error)

PasswordLogin verifies credentials and issues an ID token.

func (*Service) PasswordLoginByUserID

func (s *Service) PasswordLoginByUserID(ctx context.Context, userID, pass string, extra map[string]any) (string, time.Time, error)

PasswordLoginByUserID verifies credentials for a specific user ID and issues an ID token. This supports login flows where the identifier is a phone number or username and email may be NULL.

func (*Service) PatchOrgMetadata added in v0.4.8

func (s *Service) PatchOrgMetadata(ctx context.Context, orgID string, patch map[string]any) error

func (*Service) PatchUserMetadata added in v0.4.8

func (s *Service) PatchUserMetadata(ctx context.Context, userID string, patch map[string]any) error

func (*Service) Permissions added in v0.42.0

func (s *Service) Permissions() []PermissionDef

Permissions returns the full permission set: authkit base permissions plus the app-declared permissions (deduped, base wins on collision).

func (*Service) PlatformPermissions added in v0.42.0

func (s *Service) PlatformPermissions() []PermissionDef

PlatformPermissions returns the native `platform:` permission catalog.

func (*Service) PlatformRoleMembers added in v0.42.0

func (s *Service) PlatformRoleMembers(ctx context.Context, role string) ([]string, error)

PlatformRoleMembers returns the user ids that hold a given platform role.

func (*Service) PlatformRolesForUser added in v0.42.0

func (s *Service) PlatformRolesForUser(ctx context.Context, userID string) ([]string, error)

PlatformRolesForUser returns the platform role names assigned to a user.

func (*Service) Postgres

func (s *Service) Postgres() *pgxpool.Pool

Postgres returns the attached pgx pool (may be nil).

func (*Service) PromoteParkedOrgToRegistered added in v0.5.3

func (s *Service) PromoteParkedOrgToRegistered(ctx context.Context, slug, ownerUserID string) (orgID string, err error)

func (*Service) PromoteReservedNameToRegistered added in v0.5.3

func (s *Service) PromoteReservedNameToRegistered(ctx context.Context, slug, ownerUserID string) (orgID string, created bool, err error)

PromoteReservedNameToRegistered supports direct handoff in one operation:

restricted_name -> parked_org -> registered_org

It is idempotent for already-registered orgs and optionally ensures owner membership.

func (*Service) ProvisionOrg added in v0.30.0

ProvisionOrg applies privileged org provisioning for embedded hosts and deployment bootstrap jobs. Unlike public self-service registration, this API may create an ownerless org. Hosts that want a human-owned public org must use CreateOrgForUser.

func (*Service) PublicKeysByKID added in v0.6.0

func (s *Service) PublicKeysByKID() map[string]crypto.PublicKey

PublicKeysByKID returns the public keys indexed by key ID.

func (*Service) ReadMemberRoles added in v0.4.4

func (s *Service) ReadMemberRoles(ctx context.Context, orgSlug, userID string) ([]string, error)

func (*Service) ReconcileBootstrapManifest added in v0.37.0

func (s *Service) ReconcileBootstrapManifest(ctx context.Context, manifest BootstrapManifest, store BootstrapTokenStore, opts BootstrapReconcileOptions) (BootstrapManifestResult, error)

func (*Service) ReconcileOrgManifest added in v0.30.0

func (s *Service) ReconcileOrgManifest(ctx context.Context, manifest OrgManifest, store OrgManifestTokenStore) (OrgManifestResult, error)

ReconcileOrgManifest idempotently applies orgs, issuers, roles, and API-key outputs. It serializes reconciliation with a Postgres advisory lock so multiple replicas do not mint duplicate bootstrap tokens.

func (*Service) RecoverOrg added in v0.42.0

func (s *Service) RecoverOrg(ctx context.Context, orgID, newOwnerUserID string) (RecoverOrgResult, error)

RecoverOrg is the ANTI-TAKEOVER reset for a compromised org (#95). ATOMICALLY: revoke ALL the org's api-keys, disable ALL its remote-applications, demote ALL current members (strip every role assignment), restore a clean `owner` role (= exactly `org:*`, in case an attacker tampered with it), and assign that owner to the rightful user. Bad actors are locked out; the good owner is restored. Coarse all-or-nothing — the single sanctioned platform reach inside an org.

func (*Service) RegenerateBackupCodes

func (s *Service) RegenerateBackupCodes(ctx context.Context, userID string) ([]string, error)

RegenerateBackupCodes generates new backup codes for a user (invalidating old ones). Returns the plaintext codes (caller must show these to user ONCE).

func (*Service) RegisterRemoteAppAttributeDef added in v0.27.0

func (s *Service) RegisterRemoteAppAttributeDef(ctx context.Context, appID, key string, version int32, definition json.RawMessage) (*RemoteAppAttributeDef, error)

RegisterRemoteAppAttributeDef stores (or updates) a definition for the remote_application. version defaults to 1 when zero. The caller authority is the remote_application itself (it owns its users' restrictions); the http layer enforces that.

func (*Service) RemoteApplicationOrgRole added in v0.30.0

func (s *Service) RemoteApplicationOrgRole(ctx context.Context, orgSlug, appID string) (string, error)

RemoteApplicationOrgRole returns the role a remote_application holds in a org, or ErrNotOrgMember when it holds none.

func (*Service) RemoteApplicationOrgRoles added in v0.30.0

func (s *Service) RemoteApplicationOrgRoles(ctx context.Context, appID string) ([]OrgMembership, error)

RemoteApplicationOrgRoles returns every (org slug, role) the remote_application principal holds — the verifier uses this to resolve a remote_app's org roles, the same way it would for a user principal.

func (*Service) RemoveMember added in v0.4.4

func (s *Service) RemoveMember(ctx context.Context, orgSlug, userID string) error

func (*Service) RemoveRemoteApplicationMember added in v0.27.0

func (s *Service) RemoveRemoteApplicationMember(ctx context.Context, orgSlug, appID string) error

RemoveRemoteApplicationMember soft-deletes a remote_application's membership in a org.

func (*Service) RemoveRoleBySlug

func (s *Service) RemoveRoleBySlug(ctx context.Context, userID, slug string) error

func (*Service) RenameOrgSlug added in v0.4.4

func (s *Service) RenameOrgSlug(ctx context.Context, orgID, newSlug, actorUserID string) error

RenameOrgSlug renames a non-personal org. Subject to the 72h `renameCooldown`. Personal orgs are renamed implicitly by the user- rename flow (see service.go) and reject this entrypoint with `ErrPersonalOrgLocked`.

`actorUserID` is recorded on the rename audit row. Pass empty string when the caller doesn't have an authenticated user (e.g. internal admin tooling without an actor); the column is nullable.

func (*Service) RenameOrgSlugForce added in v0.7.0

func (s *Service) RenameOrgSlugForce(ctx context.Context, orgID, newSlug, actorUserID string) error

RenameOrgSlugForce is the admin-override variant that skips the 72h cooldown check. Otherwise identical to RenameOrgSlug. Caller is responsible for gating this behind admin scope upstream.

func (*Service) RequestEmailChange

func (s *Service) RequestEmailChange(ctx context.Context, userID, newEmail string) error

RequestEmailChange initiates an email change by sending a verification code to the new email. The current email is NOT changed until the user confirms via ConfirmEmailChange. Also sends a notification to the old email for security.

func (*Service) RequestEmailVerification

func (s *Service) RequestEmailVerification(ctx context.Context, email string, ttl time.Duration) error

RequestEmailVerification creates a verification code and dispatches an email.

func (*Service) RequestPasswordReset

func (s *Service) RequestPasswordReset(ctx context.Context, email string, ttl time.Duration, ip *string, ua *string) error

RequestPasswordReset creates a password reset token and dispatches a reset link via email. Returns nil for unknown emails to prevent user enumeration (202-like behavior).

func (*Service) RequestPhoneChange

func (s *Service) RequestPhoneChange(ctx context.Context, userID, newPhone string) error

RequestPhoneChange initiates a phone number change by sending a verification code to the new phone. The current phone is NOT changed until the user confirms via ConfirmPhoneChange.

func (*Service) RequestPhonePasswordReset

func (s *Service) RequestPhonePasswordReset(ctx context.Context, phone string, ttl time.Duration, ip *string, ua *string) error

RequestPhonePasswordReset creates a password reset token and sends a reset link via SMS. Always returns nil for unknown phone numbers to prevent user enumeration (202-like behavior).

func (*Service) RequestPhoneVerification

func (s *Service) RequestPhoneVerification(ctx context.Context, phone string, ttl time.Duration) error

RequestPhoneVerification looks up the user by phone number and sends a verification code. This mirrors the RequestEmailVerification pattern - caller only needs to provide the phone number.

func (*Service) Require2FAForLogin

func (s *Service) Require2FAForLogin(ctx context.Context, userID string) (string, error)

Require2FAForLogin sends a 2FA code to the user's configured method. Returns the destination (email/phone) where the code was sent. This should be called after successful password verification.

func (*Service) RequireFreshSession added in v0.8.3

func (s *Service) RequireFreshSession(ctx context.Context, userID, sessionID string, now time.Time) (SessionFreshness, error)

func (*Service) ResendEmailChangeCode

func (s *Service) ResendEmailChangeCode(ctx context.Context, userID string) error

ResendEmailChangeCode resends the verification code for a pending email change.

func (*Service) ResendPhoneChangeCode

func (s *Service) ResendPhoneChangeCode(ctx context.Context, userID, phone string) error

ResendPhoneChangeCode resends the verification code for a pending phone change.

func (*Service) ReserveAccount added in v0.4.8

func (s *Service) ReserveAccount(ctx context.Context, slug string) (userID, orgID string, reserved bool, err error)

ReserveAccount reserves a namespace slug without requiring a same-slug login user. For legacy placeholder rows, it still enforces non-loginable reserved invariants.

func (*Service) ResolveAPIKey added in v0.41.0

func (s *Service) ResolveAPIKey(ctx context.Context, keyID, secret string) (orgSlug string, permissions []string, err error)

ResolveAPIKey validates a presented API key (key_id + secret) and returns the owning org's current slug and the token's frozen permissions. It performs an indexed lookup by key_id, a constant-time secret compare, and revoked / expired / org-deleted checks, then best-effort async-touches last_used_at.

func (*Service) ResolveAPIKeyWithResources added in v0.41.0

func (s *Service) ResolveAPIKeyWithResources(ctx context.Context, keyID, secret string) (ResolvedAPIKey, error)

ResolveAPIKeyWithResources validates a presented API key and returns the full resource-aware result. Existing tokens with no resources return an empty Resources slice and remain org-wide for hosts that use the compatibility resolver.

func (*Service) ResolveAndStoreSolanaSNS added in v0.15.0

func (s *Service) ResolveAndStoreSolanaSNS(ctx context.Context, userID, address string) (SolanaLinkedAccount, error)

ResolveAndStoreSolanaSNS refreshes cached SNS metadata for an existing SIWS link. Resolver failures are recorded as stable metadata and do not invalidate the wallet link.

func (*Service) ResolveOrgByID added in v0.35.0

func (s *Service) ResolveOrgByID(ctx context.Context, id string) (*Org, error)

ResolveOrgByID resolves an active org by uuid string.

func (*Service) ResolveOrgBySlug added in v0.4.4

func (s *Service) ResolveOrgBySlug(ctx context.Context, slug string) (*Org, error)

ResolveOrgBySlug resolves an org by current slug or alias. Returns ErrOrgNotFound when no org matches.

func (*Service) ResolveRemoteAppAttributeDef added in v0.27.0

func (s *Service) ResolveRemoteAppAttributeDef(ctx context.Context, appID, key string, version int32) (*RemoteAppAttributeDef, error)

ResolveRemoteAppAttributeDef returns the definition for (appID, key, version). version <= 0 resolves the LATEST version. The returned Definition is opaque.

func (*Service) ResolveRemoteApplicationAuthority added in v0.28.0

func (s *Service) ResolveRemoteApplicationAuthority(ctx context.Context, appID string) (memberships []OrgMembership, permissions []string, err error)

ResolveRemoteApplicationAuthority returns a remote application's STORED authority: its org memberships (each a org slug + role names) and the effective permission set — the permissions its org roles expand to against the catalog. This is the verifier's source of truth for "what may this remote_application do AS ITSELF" (#76/#95); role claims in the token are ignored.

func (*Service) ResolveRemoteApplicationOrg added in v0.30.0

func (s *Service) ResolveRemoteApplicationOrg(ctx context.Context, issuer string) (string, error)

ResolveRemoteApplicationOrg returns the owning org_id of the remote_application registered for issuer (#77). Empty string means unowned/bootstrap-managed; ErrRemoteApplicationNotFound if unknown.

func (*Service) ResolveSessionByRefresh

func (s *Service) ResolveSessionByRefresh(ctx context.Context, refreshToken string) (string, error)

ResolveSessionByRefresh finds the session id for a presented refresh token, if valid and active.

func (*Service) ResolveUserBySlug added in v0.4.6

func (s *Service) ResolveUserBySlug(ctx context.Context, slug string) (userID string, username string, err error)

func (*Service) RestoreOrg added in v0.42.0

func (s *Service) RestoreOrg(ctx context.Context, orgID string) (bool, error)

RestoreOrg un-deletes a soft-deleted org. Returns whether a row changed.

func (*Service) RestoreUser

func (s *Service) RestoreUser(ctx context.Context, id string) error

RestoreUser clears deleted_at and re-enables the account.

func (*Service) RestrictOwnerNamespaceSlugs added in v0.5.3

func (s *Service) RestrictOwnerNamespaceSlugs(ctx context.Context, slugs []string) (restricted []string, alreadyRestricted []string, err error)

RestrictOwnerNamespaceSlugs adds slugs to the restricted-name blocklist. It is an admin operation separate from park/claim org lifecycle transitions.

func (*Service) RevokeAPIKey added in v0.41.0

func (s *Service) RevokeAPIKey(ctx context.Context, orgSlug, tokenID string) (bool, error)

RevokeAPIKey marks the API key revoked. It is scoped to the org so a token cannot be revoked from a different org. Returns false if no matching, not-already-revoked token exists.

func (*Service) RevokeAllSessions

func (s *Service) RevokeAllSessions(ctx context.Context, userID string, keepSessionID *string) error

func (*Service) RevokeOrgInvite added in v0.4.6

func (s *Service) RevokeOrgInvite(ctx context.Context, orgSlug, inviteID string) error

func (*Service) RevokeSessionByID

func (s *Service) RevokeSessionByID(ctx context.Context, sessionID string) error

func (*Service) RevokeSessionByIDForUser

func (s *Service) RevokeSessionByIDForUser(ctx context.Context, userID, sessionID string) error

RevokeSessionByIDForUser revokes a session by id ensuring it belongs to the user.

func (*Service) SMSAvailable added in v0.15.4

func (s *Service) SMSAvailable() bool

SMSAvailable reports whether phone-based flows should be offered: a sender is configured and (if a health check has run) it was found able to deliver.

func (*Service) SMSHealthReason added in v0.15.4

func (s *Service) SMSHealthReason() string

SMSHealthReason returns the reason SMS was last found unhealthy, if any.

func (*Service) SMSHealthy added in v0.15.4

func (s *Service) SMSHealthy() bool

SMSHealthy reports the last CheckSMSHealth result. It is true until a check has run (legacy behavior: assume healthy when a sender is present).

func (*Service) Schema added in v0.26.0

func (s *Service) Schema() string

Schema returns the Postgres schema AuthKit's tables live in ("profiles" unless configured otherwise via Config.Schema/Options.Schema).

func (*Service) SendPhone2FASetupCode

func (s *Service) SendPhone2FASetupCode(ctx context.Context, userID, phone, code string) error

SendPhone2FASetupCode generates and sends a 6-digit code for 2FA setup to the user's phone.

func (*Service) SendPhoneVerificationToUser

func (s *Service) SendPhoneVerificationToUser(ctx context.Context, phone, userID string, ttl time.Duration) error

SendPhoneVerificationToUser creates a verification code and sends it via SMS to a known user. Use RequestPhoneVerification if you only have a phone number and need to look up the user. Always returns nil for security.

func (*Service) SendWelcome

func (s *Service) SendWelcome(ctx context.Context, userID string)

SendWelcome triggers the welcome email if an EmailSender is configured.

func (*Service) SessionFreshness added in v0.8.3

func (s *Service) SessionFreshness(ctx context.Context, userID, sessionID string, now time.Time) (SessionFreshness, error)

func (*Service) SetEmailVerified

func (s *Service) SetEmailVerified(ctx context.Context, id string, v bool) error

func (*Service) SetOrgNamespaceState added in v0.5.3

func (s *Service) SetOrgNamespaceState(ctx context.Context, orgID string, state OwnerNamespaceState) error

func (*Service) SetPasswordAfterFreshAuth added in v0.8.3

func (s *Service) SetPasswordAfterFreshAuth(ctx context.Context, userID, new string, keepSessionID *string) error

func (*Service) SetPlatformRolePermissions added in v0.42.0

func (s *Service) SetPlatformRolePermissions(ctx context.Context, role string, perms []string) error

SetPlatformRolePermissions replaces a platform role's permission set. The role must exist. Tokens are stored as-is; callers should ValidatePlatformGrant first.

func (*Service) SetPreferredLocale added in v0.14.0

func (s *Service) SetPreferredLocale(ctx context.Context, userID, locale, source string) error

func (*Service) SetProviderUsername

func (s *Service) SetProviderUsername(ctx context.Context, userID, provider, subject, username string) error

func (*Service) SetRolePermissions added in v0.11.3

func (s *Service) SetRolePermissions(ctx context.Context, orgSlug, role string, perms []string) error

SetRolePermissions replaces a role's permission set (idempotent). The role must already exist (created via DefineRole). Tokens are stored as-is (opaque); callers should validate via ValidateGrant first for no-escalation.

func (*Service) SoftDeleteOrg added in v0.42.0

func (s *Service) SoftDeleteOrg(ctx context.Context, orgID string) (bool, error)

SoftDeleteOrg soft-deletes an org (sets deleted_at). Returns whether a row changed. AuthKit's soft-delete does NOT cascade APP-owned resources (the app reacts to org-deletion for its own cleanup).

func (*Service) SoftDeleteUser

func (s *Service) SoftDeleteUser(ctx context.Context, id string) error

SoftDeleteUser marks the user deleted and sets deleted_at without dropping rows. Also revokes all refresh sessions for this issuer.

func (*Service) TimeUntilOrgRenameAvailable added in v0.9.4

func (s *Service) TimeUntilOrgRenameAvailable(ctx context.Context, orgID string, now time.Time) (int64, error)

func (*Service) TimeUntilUsernameRenameAvailable added in v0.8.6

func (s *Service) TimeUntilUsernameRenameAvailable(ctx context.Context, userID string, now time.Time) (int64, error)

func (*Service) UnassignPlatformRole added in v0.42.0

func (s *Service) UnassignPlatformRole(ctx context.Context, userID, role string) (bool, error)

UnassignPlatformRole revokes a user's platform role. Returns whether a row was removed.

func (*Service) UnassignRole added in v0.4.4

func (s *Service) UnassignRole(ctx context.Context, orgSlug, userID, role string) error

func (*Service) UnbanUser

func (s *Service) UnbanUser(ctx context.Context, userID string) error

UnbanUser clears ban metadata and re-enables the account.

func (*Service) UnlinkProvider

func (s *Service) UnlinkProvider(ctx context.Context, userID, provider string) error

func (*Service) UnrestrictOwnerNamespaceSlugs added in v0.5.3

func (s *Service) UnrestrictOwnerNamespaceSlugs(ctx context.Context, slugs []string) (unrestricted []string, notRestricted []string, err error)

UnrestrictOwnerNamespaceSlugs removes slugs from the restricted-name blocklist.

func (*Service) UpdateBiography

func (s *Service) UpdateBiography(ctx context.Context, id string, bio *string) error

func (*Service) UpdateEmail

func (s *Service) UpdateEmail(ctx context.Context, id, email string) error

func (*Service) UpdateImportedUser added in v0.9.0

func (s *Service) UpdateImportedUser(ctx context.Context, userID string, input ImportUserInput) (*User, error)

func (*Service) UpdateUsername

func (s *Service) UpdateUsername(ctx context.Context, id, username string) error

func (*Service) UpdateUsernameForce added in v0.7.0

func (s *Service) UpdateUsernameForce(ctx context.Context, id, username string) error

UpdateUsernameForce is the admin override that skips the 72h cooldown check. Otherwise identical to UpdateUsername. Caller is responsible for gating this behind admin scope upstream.

func (*Service) UpsertPasswordHash

func (s *Service) UpsertPasswordHash(ctx context.Context, userID, hash, algo string, params []byte) error

func (*Service) UpsertRemoteApplication added in v0.27.0

func (s *Service) UpsertRemoteApplication(ctx context.Context, in RemoteApplication) (*RemoteApplication, error)

UpsertRemoteApplication registers or updates a remote_application keyed by its issuer. OrgID is optional: empty rows are bootstrap/operator-managed.

func (*Service) UpsertRoleBySlug added in v0.9.0

func (s *Service) UpsertRoleBySlug(ctx context.Context, name, slug string, description *string) error

func (*Service) ValidateGrant added in v0.11.3

func (s *Service) ValidateGrant(ctx context.Context, orgSlug, actorUserID string, tokens []string, actorAll bool) (unknown, offending []string, err error)

ValidateGrant checks a set of permission tokens an actor wants to assign to a role (#94 no-escalation, #95 glob model). Each token must EXPAND to at least one catalog permission (else returned in unknown — a bare `*`, a typo, or a glob matching nothing is invalid). No-escalation: the actor must already hold EVERY concrete permission the token expands to (else the token is returned in offending) — so granting `org:members:*` requires holding all of `org:members:*`. `actorAll` short-circuits the no-escalation check for an actor known to hold everything (bootstrap system-actor / platform admin). Returns (unknown, offending).

func (*Service) ValidateInviteRoleGrant added in v0.29.0

func (s *Service) ValidateInviteRoleGrant(ctx context.Context, orgSlug, grantorUserID, role string) error

ValidateInviteRoleGrant enforces the no-escalation invariant for a org invite: the GRANTOR (the inviter) must currently hold every permission the invited role confers. A global admin or an actor holding `*` passes. Returns ErrInviteRoleExceedsGrantor when the grantor's authority is insufficient.

Called at invite-create time AND re-checked at accept time, since the inviter's permissions may have been reduced between creating the invite and the invitee accepting it (a stale pending "owner" invite must not still grant owner once its creator has been demoted).

func (*Service) ValidatePlatformGrant added in v0.42.0

func (s *Service) ValidatePlatformGrant(ctx context.Context, actorUserID string, tokens []string, actorAll bool) (unknown, offending []string, err error)

ValidatePlatformGrant checks tokens an actor wants to assign to a platform role (#94 no-escalation + #95 DISJOINT namespaces). Each token must (a) be in the `platform:` namespace — an `org:` perm, a bare `*`, or a `!`-negation is REJECTED as unknown (keeping the two layers disjoint) — and (b) expand to at least one platform catalog permission. No-escalation: the actor must already hold every concrete platform permission the token confers. `actorAll` short-circuits for a bootstrap/super-admin actor. Returns (unknown, offending).

func (*Service) ValidateUsernameForRegistration added in v0.8.6

func (s *Service) ValidateUsernameForRegistration(ctx context.Context, username string) (string, error)

func (*Service) ValidateUsernameForUser added in v0.8.6

func (s *Service) ValidateUsernameForUser(ctx context.Context, username, userID string) (slug, excludeOrgID string, err error)

func (*Service) ValidateVerificationConfiguration added in v0.5.0

func (s *Service) ValidateVerificationConfiguration() error

ValidateVerificationConfiguration ensures registration verification policy can be satisfied by currently configured delivery senders.

func (*Service) Verify2FAChallenge

func (s *Service) Verify2FAChallenge(ctx context.Context, userID, challenge string) (bool, error)

Verify2FAChallenge verifies the challenge created during the password step.

func (*Service) Verify2FACode

func (s *Service) Verify2FACode(ctx context.Context, userID, code string) (bool, error)

Verify2FACode verifies a 2FA code entered by the user during login. Returns true if code is valid, false otherwise.

func (*Service) VerifyBackupCode

func (s *Service) VerifyBackupCode(ctx context.Context, userID, backupCode string) (bool, error)

VerifyBackupCode verifies a 2FA backup code for account recovery. On success, removes the used backup code from the user's backup codes.

func (*Service) VerifyPendingPassword

func (s *Service) VerifyPendingPassword(ctx context.Context, email, pass string) bool

VerifyPendingPassword checks if the provided password matches the pending registration's hash. Returns true if password is correct, false otherwise.

func (*Service) VerifyPendingPhonePassword added in v0.15.4

func (s *Service) VerifyPendingPhonePassword(ctx context.Context, phone, pass string) bool

VerifyPendingPhonePassword checks if the provided password matches the pending phone registration's hash. Returns true if password is correct, false otherwise.

func (*Service) VerifyPhone2FASetupCode

func (s *Service) VerifyPhone2FASetupCode(ctx context.Context, userID, phone, code string) (bool, error)

VerifyPhone2FASetupCode checks the code for 2FA phone setup.

func (*Service) VerifySIWSAndLogin

func (s *Service) VerifySIWSAndLogin(ctx context.Context, cache siws.ChallengeCache, output siws.SignInOutput, extra map[string]any) (accessToken string, expiresAt time.Time, refreshToken, userID string, created bool, err error)

VerifySIWSAndLogin verifies a SIWS signature and logs in or creates a user. Returns access token, expiry, refresh token, user ID, and whether a new user was created.

func (*Service) VerifyUserPassword added in v0.5.1

func (s *Service) VerifyUserPassword(ctx context.Context, userID, pass string) bool

VerifyUserPassword checks a user's password without issuing tokens or updating last-login. Returns true if the password is correct, false otherwise.

func (*Service) WithAuthLogger

func (s *Service) WithAuthLogger(l AuthEventLogger) *Service

WithAuthLogger sets the authentication event logger (e.g., ClickHouse sink).

func (*Service) WithEmailSender

func (s *Service) WithEmailSender(sender EmailSender) *Service

WithEmailSender sets the email sender dependency.

func (*Service) WithEntitlements

func (s *Service) WithEntitlements(p EntitlementsProvider) *Service

WithEntitlements sets the entitlements provider.

func (*Service) WithEphemeralStore

func (s *Service) WithEphemeralStore(store EphemeralStore, mode EphemeralMode) *Service

func (*Service) WithPostgres

func (s *Service) WithPostgres(pool *pgxpool.Pool) *Service

WithPostgres attaches a pgx pool to the service. The pool is shared with the host; AuthKit never mutates it (in particular it never sets search_path — queries stay schema-qualified, rewritten to s.Schema() when non-default).

func (*Service) WithSMSSender

func (s *Service) WithSMSSender(sender SMSSender) *Service

WithSMSSender sets the SMS sender dependency.

type ServiceJWTClaims added in v0.13.1

type ServiceJWTClaims struct {
	Issuer      string
	Subject     string
	Audiences   []string
	IssuedAt    time.Time
	NotBefore   time.Time
	ExpiresAt   time.Time
	JTI         string
	TokenUse    string
	Permissions []string
	Resources   []APIKeyResource
	Scope       []string
}

ServiceJWTClaims is the canonical AuthKit claim shape for caller-minted machine-to-machine JWTs. Permissions are requested capabilities; receiving services must still intersect them with server-side grants.

func MintServiceJWT added in v0.13.1

func MintServiceJWT(ctx context.Context, signer jwtkit.Signer, issuer string, opts ServiceJWTMintOptions) (string, ServiceJWTClaims, error)

MintServiceJWT signs a service JWT with an explicit signer and issuer. Hosts can use this helper when they manage the signing key outside core.Service.

type ServiceJWTMintOptions added in v0.13.1

type ServiceJWTMintOptions struct {
	Subject     string
	Audiences   []string
	Permissions []string
	Resources   []APIKeyResource
	Lifetime    time.Duration
	NotBefore   time.Time
	IssuedAt    time.Time
	JTI         string
}

ServiceJWTMintOptions controls service-JWT minting for embedded hosts.

type Session

type Session struct {
	ID                  string
	FamilyID            string
	CreatedAt           time.Time
	LastAuthenticatedAt *time.Time
	LastUsedAt          time.Time
	ExpiresAt           *time.Time
	RevokedAt           *time.Time
	UserAgent           *string
	IPAddr              *string
}

Session represents a sanitized session view (no tokens).

type SessionEventType

type SessionEventType string

SessionEventType identifies a session lifecycle event.

const (
	SessionEventCreated          SessionEventType = "session_created"
	SessionEventRevoked          SessionEventType = "session_revoked"
	SessionEventPasswordChange   SessionEventType = "password_changed"
	SessionEventPasswordRecovery SessionEventType = "password_recovery"
	SessionEventFailed           SessionEventType = "session_failed"
)

type SessionFreshness added in v0.8.3

type SessionFreshness struct {
	LastAuthenticatedAt           time.Time
	TimeUntilReauthRequired       time.Duration
	ReauthRequiredForSensitiveOps bool
}

type SessionRevokeReason

type SessionRevokeReason string

SessionRevokeReason identifies why a session (or set of sessions) was revoked.

const (
	SessionRevokeReasonUnknown              SessionRevokeReason = ""
	SessionRevokeReasonLogout               SessionRevokeReason = "logout"
	SessionRevokeReasonUserRevoke           SessionRevokeReason = "user_revoke"
	SessionRevokeReasonUserRevokeAll        SessionRevokeReason = "user_revoke_all"
	SessionRevokeReasonAdminRevoke          SessionRevokeReason = "admin_revoke"
	SessionRevokeReasonAdminRevokeAll       SessionRevokeReason = "admin_revoke_all"
	SessionRevokeReasonPasswordChange       SessionRevokeReason = "password_change"
	SessionRevokeReasonAdminSetPassword     SessionRevokeReason = "admin_set_password"
	SessionRevokeReasonUserDisabled         SessionRevokeReason = "user_disabled"
	SessionRevokeReasonBanned               SessionRevokeReason = "banned"
	SessionRevokeReasonSoftDeleted          SessionRevokeReason = "soft_deleted"
	SessionRevokeReasonEvicted              SessionRevokeReason = "evicted"
	SessionRevokeReasonRefreshReuseDetected SessionRevokeReason = "refresh_reuse_detected"
)

type SolanaLinkedAccount added in v0.15.0

type SolanaLinkedAccount struct {
	Provider            string     `json:"provider"`
	Issuer              string     `json:"issuer"`
	Address             string     `json:"address"`
	Verified            bool       `json:"verified"`
	VerifiedAt          *time.Time `json:"verified_at"`
	PrimarySNSName      *string    `json:"primary_sns_name"`
	SNSResolutionStatus string     `json:"sns_resolution_status"`
	SNSResolvedAt       *time.Time `json:"sns_resolved_at"`
	SNSStale            bool       `json:"sns_stale"`
	SNSError            *string    `json:"sns_error"`
}

SolanaLinkedAccount is the AuthKit-owned normalized metadata for a SIWS-linked wallet.

type SolanaSNSResolver added in v0.15.0

type SolanaSNSResolver interface {
	ResolvePrimaryName(ctx context.Context, address string) (string, error)
}

SolanaSNSResolver resolves a verified Solana wallet address to its primary .sol name.

type TwoFactorSettings

type TwoFactorSettings struct {
	UserID      string
	Enabled     bool
	Method      string // "email" or "sms"
	PhoneNumber *string
	BackupCodes []string // Hashed backup codes
	CreatedAt   time.Time
	UpdatedAt   time.Time
}

TwoFactorSettings represents a user's 2FA configuration

type User

type User struct {
	ID              string
	Email           *string // Nullable - phone-only users have NULL email
	PhoneNumber     *string
	Username        *string
	DiscordUsername *string
	EmailVerified   bool
	PhoneVerified   bool
	BannedAt        *time.Time
	BannedUntil     *time.Time
	BanReason       *string
	BannedBy        *string
	DeletedAt       *time.Time
	Biography       *string
	CreatedAt       time.Time
	UpdatedAt       time.Time
	LastLogin       *time.Time
}

type ValidationError added in v0.8.6

type ValidationError struct {
	Code              string
	RetryAfterSeconds int64
}

ValidationError is the stable identity-policy error returned by AuthKit validation helpers. Code is intended to be exposed directly in route responses as {"error":"code"}.

func (*ValidationError) Error added in v0.8.6

func (e *ValidationError) Error() string

type VerificationMessage added in v0.5.0

type VerificationMessage struct {
	// Fixed-length numeric code for manual entry (optional).
	Code string
	// High-entropy token for one-click verification link flow (optional).
	LinkToken string
}

func (VerificationMessage) Validate added in v0.5.0

func (m VerificationMessage) Validate() error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL