auth

package
v0.4.0 Latest Latest
Warning

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

Go to latest
Published: Jul 25, 2026 License: AGPL-3.0 Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
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
)
View Source
const (
	AccessTokenDuration    = 15 * time.Minute
	RefreshTokenDuration   = 7 * 24 * time.Hour
	SubdomainTokenDuration = time.Hour
)
View Source
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.

View Source
const RecentAuthenticationWindow = 10 * time.Minute

Variables

View Source
var ErrInvalidAudience = errors.New("invalid token audience")
View Source
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

func AgentIDFromContext(ctx interface{ Value(any) any }) uuid.UUID

AgentIDFromContext returns the agent UUID from context, set by AgentMiddleware.

func AgentMiddleware

func AgentMiddleware(jwtSecret string, q agentTokenQuerier) func(http.Handler) http.Handler

AgentMiddleware validates the agent JWT and its live database state on every request, then injects AgentClaims into context.

func BearerToken added in v0.4.0

func BearerToken(header string) (string, error)

BearerToken extracts a strict Authorization bearer token.

func CheckPassword

func CheckPassword(hash, password string) error

CheckPassword compares a plaintext password with a bcrypt hash. Returns nil on success, error on mismatch.

func GenerateTempPassword added in v0.4.0

func GenerateTempPassword() (string, error)

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

func HashIntegrationToken(token string) []byte

HashIntegrationToken validates and hashes an integration token for lookup. Invalid token shapes return nil so they cannot match a database row.

func HashPassword

func HashPassword(password string) (string, error)

HashPassword hashes a plaintext password using bcrypt.

func IssueAgentToken

func IssueAgentToken(secret string, agentID uuid.UUID, tokenVersion int64) (string, error)

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

func LiveSessionMiddleware(database *db.DB) func(http.Handler) http.Handler

LiveSessionMiddleware verifies the active DB session and replaces token snapshots with the current user role and account-security state.

func Middleware

func Middleware(jwtSecret string) func(http.Handler) http.Handler

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

func NewIntegrationToken() (string, []byte, error)

NewIntegrationToken returns a build-scoped bearer token and the hash Airlock stores. The plaintext token exists only in the codegen toolserver environment.

func RequireRecentAuthentication added in v0.4.0

func RequireRecentAuthentication(next http.Handler) http.Handler

RequireRecentAuthentication protects credential mutations. Forced-password users may reach only the narrowly allowlisted account-securing operations.

func RequireTenantRole

func RequireTenantRole(minRole Role) func(http.Handler) http.Handler

RequireTenantRole returns middleware that checks the user has at least the given role. Uses hierarchy: admin > manager > user. Returns 403 if not authorized.

func ScopeContains added in v0.4.0

func ScopeContains(scope, required string) bool

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

func SessionIDFromContext(ctx context.Context) uuid.UUID

SessionIDFromContext returns the current first-party session ID, if present.

func UserIDFromContext

func UserIDFromContext(ctx context.Context) uuid.UUID

UserIDFromContext returns the user ID from the JWT claims.

func ValidatePasswordStrength added in v0.4.0

func ValidatePasswordStrength(password string, userInputs []string) error

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 the user's display name, carried so proxied agent
	// requests can forward it (X-User-Name) without a DB lookup. Display
	// claim only — never used for authorization. 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"`
}

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 ClaimsFromContext

func ClaimsFromContext(ctx context.Context) *Claims

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 ValidateOAuthAccessToken added in v0.4.0

func ValidateOAuthAccessToken(secret, tokenString, audience string) (*Claims, error)

ValidateOAuthAccessToken accepts only OAuth MCP tokens for audience.

func ValidateRefreshToken added in v0.4.0

func ValidateRefreshToken(secret, tokenString string) (*Claims, error)

ValidateRefreshToken accepts only signed refresh-profile tokens.

func ValidateSubdomainToken added in v0.4.0

func ValidateSubdomainToken(secret, tokenString string, targetAgentID uuid.UUID) (*Claims, error)

ValidateSubdomainToken accepts only a subdomain token bound to targetAgentID.

func ValidateUserAccessToken added in v0.4.0

func ValidateUserAccessToken(secret, tokenString string) (*Claims, error)

ValidateUserAccessToken accepts only first-party user access tokens.

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.

const (
	RoleAdmin   Role = "admin"
	RoleManager Role = "manager"
	RoleUser    Role = "user"
)

func (Role) AtLeast added in v0.4.0

func (r Role) AtLeast(min Role) bool

AtLeast reports whether r ranks at or above min. An unknown role (including the empty string) ranks below everything.

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.

Jump to

Keyboard shortcuts

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