Documentation
¶
Index ¶
- Constants
- Variables
- func AgentIDFromContext(ctx interface{ ... }) uuid.UUID
- func AgentMiddleware(jwtSecret string, q agentTokenQuerier) func(http.Handler) http.Handler
- func AgentTokenVersionFromContext(ctx interface{ ... }) int64
- func BearerToken(header string) (string, error)
- func CheckPassword(hash, password string) error
- func GenerateTempPassword() (string, error)
- func HashIntegrationToken(token string) []byte
- func HashPassword(password string) (string, error)
- func IssueAgentToken(secret string, agentID uuid.UUID, tokenVersion int64) (string, error)
- func IssueOAuthAccessToken(secret string, userID uuid.UUID, ...) (string, error)
- func IssueRefreshToken(secret string, userID uuid.UUID, email, displayName, tenantRole string, ...) (string, error)
- func IssueSubdomainToken(secret string, targetAgentID, userID, sessionID uuid.UUID, ...) (string, error)
- func IssueToken(secret string, userID uuid.UUID, email, displayName, tenantRole string, ...) (string, error)
- func IssueUserAccessToken(secret string, userID uuid.UUID, email, displayName, tenantRole string, ...) (string, error)
- func LiveSessionMiddleware(database *db.DB) func(http.Handler) http.Handler
- func Middleware(jwtSecret string) func(http.Handler) http.Handler
- func NewIntegrationToken() (string, []byte, error)
- func RequestBearerToken(r *http.Request) (token string, supplied bool, err error)
- func RequestScheme(r *http.Request) string
- func RequireRecentAuthentication(next http.Handler) http.Handler
- func RequireSecuredAccount(claims *Claims) error
- func ScopeContains(scope, required string) bool
- func SessionIDFromContext(ctx context.Context) uuid.UUID
- func UniqueCookie(r *http.Request, name string) (*http.Cookie, error)
- func UserIDFromContext(ctx context.Context) uuid.UUID
- func ValidatePasswordStrength(password string, userInputs []string) error
- func WithAuthenticatedProxyScheme(ctx context.Context, scheme string) context.Context
- type AgentClaims
- type Claims
- func AdmitBridge(ctx context.Context, q *dbq.Queries, bridgeID uuid.UUID, ...) (*Claims, error)
- func AdmitOAuthAccess(ctx context.Context, q *dbq.Queries, secret, token, audience string) (*Claims, error)
- func AdmitSubdomain(r *http.Request, q *dbq.Queries, secret string, agentID uuid.UUID) (claims *Claims, fromCookie, supplied bool, err error)
- func AdmitUserAccess(ctx context.Context, q *dbq.Queries, secret, token string) (*Claims, error)
- func ClaimsFromContext(ctx context.Context) *Claims
- func ResolveLiveUserClaims(ctx context.Context, q *dbq.Queries, claims *Claims, requireSession bool) (*Claims, error)
- func RestoreRunIdentity(ctx context.Context, q *dbq.Queries, runID uuid.UUID) (*Claims, error)
- func RestoreSystemRunIdentity(ctx context.Context, q *dbq.Queries, runID uuid.UUID) (*Claims, error)
- func ValidateOAuthAccessToken(secret, tokenString, audience string) (*Claims, error)
- func ValidateRefreshToken(secret, tokenString string) (*Claims, error)
- func ValidateSubdomainToken(secret, tokenString string, targetAgentID uuid.UUID) (*Claims, error)
- func ValidateUserAccessToken(secret, tokenString string) (*Claims, error)
- type Identity
- type Provenance
- type Role
Constants ¶
const ( // AgentTokenDuration bounds exposure while leaving ample time for a run to // finish. Containers are proactively replaced before this window closes. AgentTokenDuration = 7 * 24 * time.Hour // AgentTokenRotationWindow is the minimum lifetime required when reusing a // running container. AgentTokenRotationWindow = 24 * time.Hour )
const ( AccessTokenDuration = 15 * time.Minute RefreshTokenDuration = 7 * 24 * time.Hour SubdomainTokenDuration = time.Hour )
const MinPasswordScore = 3
MinPasswordScore is the minimum acceptable zxcvbn strength score (0–4) for a user-chosen password. The frontend meter enforces the same threshold via @zxcvbn-ts, so "acceptable" means the same thing on both sides and a password the meter shows as green is one the backend will accept. 3 ("safely unguessable") is the floor for an internet-facing login.
const RecentAuthenticationWindow = 10 * time.Minute
Variables ¶
var ErrInvalidAudience = errors.New("invalid token audience")
var ErrRunAuthorityRevoked = errors.New("run authority revoked")
ErrRunAuthorityRevoked marks a denial established by authoritative persisted state. Lookup failures and delivery lease expiry must not carry this marker.
var ErrWeakPassword = errors.New("password is too weak: choose a longer or less predictable password")
ErrWeakPassword is returned by ValidatePasswordStrength for passwords below MinPasswordScore.
Functions ¶
func AgentIDFromContext ¶
AgentIDFromContext returns the agent UUID from context, set by AgentMiddleware.
func AgentMiddleware ¶
AgentMiddleware validates the agent JWT and its live database state on every request, then injects AgentClaims into context.
func AgentTokenVersionFromContext ¶ added in v0.5.0
AgentTokenVersionFromContext returns the authenticated runtime generation.
func BearerToken ¶ added in v0.4.0
BearerToken extracts a strict Authorization bearer token.
func CheckPassword ¶
CheckPassword compares a plaintext password with a bcrypt hash. Returns nil on success, error on mismatch.
func GenerateTempPassword ¶ added in v0.4.0
GenerateTempPassword returns a random, high-entropy temporary password (lowercase base32, 24 chars). Used for admin-provisioned users and the `airlock auth reset` break-glass; the recipient is forced to change it or register a passkey on first login. It comfortably clears MinPasswordScore.
func HashIntegrationToken ¶ added in v0.4.0
HashIntegrationToken validates and hashes an integration token for lookup. Invalid token shapes return nil so they cannot match a database row.
func HashPassword ¶
HashPassword hashes a plaintext password using bcrypt.
func IssueAgentToken ¶
IssueAgentToken creates a versioned JWT for an agent container.
func IssueOAuthAccessToken ¶ added in v0.4.0
func IssueOAuthAccessToken(secret string, userID uuid.UUID, email, tenantRole, clientID, scope, audience string, authEpoch int64) (string, error)
IssueOAuthAccessToken mints a JWT with the OAuth-side claims set (ClientID + Scope + Audience). 15-min lifetime, same HS256 secret as the web-login tokens.
This is the sole issuer that sets ClientID. The OAuth validator requires it together with the OAuth issuer, token use, scope, and target audience.
audience is the canonical resource URL, e.g. "https://airlock.example.com/api/agent/<uuid>/mcp". scope is the space-delimited scope string ("mcp" in v1).
func IssueRefreshToken ¶
func IssueRefreshToken(secret string, userID uuid.UUID, email, displayName, tenantRole string, mustChangePassword bool) (string, error)
IssueRefreshToken creates a signed refresh token (7 days).
func IssueSubdomainToken ¶ added in v0.4.0
func IssueSubdomainToken(secret string, targetAgentID, userID, sessionID uuid.UUID, email, displayName, tenantRole string, authEpoch int64) (string, error)
IssueSubdomainToken creates a short-lived user identity token bound to one agent subdomain.
func IssueToken ¶
func IssueToken(secret string, userID uuid.UUID, email, displayName, tenantRole string, mustChangePassword bool) (string, error)
IssueToken creates a signed access token (15 min).
func IssueUserAccessToken ¶ added in v0.4.0
func IssueUserAccessToken(secret string, userID uuid.UUID, email, displayName, tenantRole string, mustChangePassword bool, sessionID uuid.UUID, authEpoch int64, authTime time.Time) (string, error)
IssueUserAccessToken creates a session-bound first-party access token.
func LiveSessionMiddleware ¶ added in v0.4.0
LiveSessionMiddleware verifies the active DB session and replaces token snapshots with the current user role and account-security state.
func Middleware ¶
Middleware validates the JWT Bearer token and injects claims into context. It returns 401 for missing, invalid, or expired tokens.
func NewIntegrationToken ¶ added in v0.4.0
NewIntegrationToken returns a build-scoped bearer token and the hash Airlock stores. The plaintext token exists only in the codegen toolserver environment.
func RequestBearerToken ¶
RequestBearerToken rejects ambiguous credentials, including duplicate header lines. An absent header is distinct from a supplied empty or malformed header.
func RequestScheme ¶
func RequireRecentAuthentication ¶ added in v0.4.0
RequireRecentAuthentication protects credential mutations. Forced-password users may reach only the narrowly allowlisted account-securing operations.
func RequireSecuredAccount ¶
RequireSecuredAccount is shared by non-recovery admission surfaces.
func ScopeContains ¶ added in v0.4.0
ScopeContains reports whether `required` is present in a space-delimited scope string. OAuth 2.0 scopes are case-sensitive (RFC 6749 §3.3); we match exactly.
func SessionIDFromContext ¶ added in v0.4.0
SessionIDFromContext returns the current first-party session ID, if present.
func UniqueCookie ¶
UniqueCookie rejects cookie shadowing across paths and domains.
func UserIDFromContext ¶
UserIDFromContext returns the user ID from the JWT claims.
func ValidatePasswordStrength ¶ added in v0.4.0
ValidatePasswordStrength rejects weak passwords using zxcvbn. userInputs are context strings (email, display name) that count against the score when the password contains them. Returns nil when the password is strong enough.
Types ¶
type AgentClaims ¶
type AgentClaims struct {
jwt.RegisteredClaims
AgentID string `json:"agent_id"`
TokenUse string `json:"token_use"`
Profile string `json:"profile"`
TokenVersion int64 `json:"token_version"`
}
AgentClaims are the JWT claims for agent tokens.
func ValidateAgentToken ¶
func ValidateAgentToken(secret, tokenString string) (*AgentClaims, error)
ValidateAgentToken validates a JWT and returns the agent claims. Rejects tokens that do not have an AgentID claim.
type Claims ¶
type Claims struct {
jwt.RegisteredClaims
Email string `json:"email"`
// DisplayName is presentation metadata, never authorization. Admission
// refreshes it from the live account. Empty for OAuth/MCP tokens.
DisplayName string `json:"name,omitempty"`
TenantRole string `json:"tenant_role"`
ClientID string `json:"client_id,omitempty"`
Scope string `json:"scope,omitempty"`
AgentID string `json:"agent_id,omitempty"`
TokenUse string `json:"token_use"`
SessionID string `json:"sid,omitempty"`
AuthEpoch int64 `json:"auth_epoch"`
AuthTime *jwt.NumericDate `json:"auth_time,omitempty"`
// MustChangePassword mirrors users.must_change_password. When true the
// /api/v1 secured-account gate restricts the token to the account-securing
// endpoints until the user sets a strong password or registers a passkey,
// then receives a fresh token with the flag cleared. Web-login tokens carry
// the live value at issue; OAuth/MCP tokens never set it.
MustChangePassword bool `json:"must_change_password,omitempty"`
// contains filtered or unexported fields
}
Claims are the JWT claims for Airlock tokens.
ClientID and Scope are populated only on OAuth MCP access tokens. AgentID is populated only on subdomain tokens. TokenUse, issuer, and audience identify the token profile; validators require all three.
func AdmitBridge ¶
func AdmitBridge(ctx context.Context, q *dbq.Queries, bridgeID uuid.UUID, senderID, chatID string) (*Claims, error)
AdmitBridge admits a private message received by Airlock's authenticated Telegram poller. A transport supplies platform coordinates, never an Airlock user UUID or role. Linked identity and account state are resolved live.
func AdmitOAuthAccess ¶
func AdmitOAuthAccess(ctx context.Context, q *dbq.Queries, secret, token, audience string) (*Claims, error)
AdmitOAuthAccess validates the MCP profile, exact configured resource audience, live account epoch, client, and grant. OAuth carries no web session.
func AdmitSubdomain ¶
func AdmitSubdomain(r *http.Request, q *dbq.Queries, secret string, agentID uuid.UUID) (claims *Claims, fromCookie, supplied bool, err error)
AdmitSubdomain accepts exactly one explicit user bearer or one agent-bound cookie. Missing credentials are distinct from invalid supplied credentials.
func AdmitUserAccess ¶
AdmitUserAccess performs profile validation and live first-party admission. Account recovery endpoints apply their narrow secured-account allowlist.
func ClaimsFromContext ¶
ClaimsFromContext retrieves the JWT claims from the context.
func ResolveLiveUserClaims ¶ added in v0.4.0
func ResolveLiveUserClaims(ctx context.Context, q *dbq.Queries, claims *Claims, requireSession bool) (*Claims, error)
ResolveLiveUserClaims rejects tokens for deleted users, stale auth epochs, and, when requireSession is true, revoked or expired first-party sessions. It returns authorization claims populated from the current user row.
func RestoreRunIdentity ¶
RestoreRunIdentity reads only immutable, host-written run origin records. No API accepts raw Provenance as a credential. Durable jobs return live account claims without a transferable Identity: their authorization must be resolved from this run again for every operation, independent of browser token lifetime.
func RestoreSystemRunIdentity ¶
func RestoreSystemRunIdentity(ctx context.Context, q *dbq.Queries, runID uuid.UUID) (*Claims, error)
RestoreSystemRunIdentity accepts only the key of a private, immutable system run origin. It never treats a user row or caller-supplied provenance as proof.
func ValidateOAuthAccessToken ¶ added in v0.4.0
ValidateOAuthAccessToken accepts only OAuth MCP tokens for audience.
func ValidateRefreshToken ¶ added in v0.4.0
ValidateRefreshToken accepts only signed refresh-profile tokens.
func ValidateSubdomainToken ¶ added in v0.4.0
ValidateSubdomainToken accepts only a subdomain token bound to targetAgentID.
func ValidateUserAccessToken ¶ added in v0.4.0
ValidateUserAccessToken accepts only first-party user access tokens.
type Identity ¶
type Identity struct {
// contains filtered or unexported fields
}
Identity retains verified credential provenance without exposing mutable authorization claims. Token validation or authenticated platform admission produces one. It can be rechecked at each action in a long-running turn.
func (*Identity) Provenance ¶
func (i *Identity) Provenance() Provenance
type Provenance ¶
type Provenance struct {
Profile string
UserID uuid.UUID
SessionID uuid.UUID
AuthEpoch int64
ExpiresAt time.Time
AuthenticatedAt time.Time
Audience string
ClientID string
Scope string
AgentID uuid.UUID
BridgeID uuid.UUID
PlatformIdentityID uuid.UUID
SenderID string
ChatID string
}
Provenance contains credential coordinates for durable run attribution. It contains no role or access authority and cannot be used to construct Identity.
type Role ¶ added in v0.4.0
type Role string
Role is a tenant role — what a user can do in Airlock as a platform, independent of any per-agent access. Mirrors agentsdk.Access (the per-agent axis) so the two gates read the same way.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package lockout implements per-(email, ip) login throttling for the airlock auth path.
|
Package lockout implements per-(email, ip) login throttling for the airlock auth path. |
|
Package passkey wraps go-webauthn for airlock's human login.
|
Package passkey wraps go-webauthn for airlock's human login. |