Documentation
¶
Overview ¶
Package token provides JWT claims and token handling for registry authentication.
Index ¶
- Constants
- func ExtractAccess(tokenString string) []auth.AccessEntry
- func ExtractAuthMethod(tokenString string) string
- func ExtractSubject(tokenString string) string
- func HasPushScope(access []auth.AccessEntry) bool
- type AuthErrorResponse
- type Authorizer
- type Claims
- type Handler
- func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (h *Handler) SetAuthorizer(authorizer Authorizer)
- func (h *Handler) SetOAuthSessionValidator(validator OAuthSessionValidator)
- func (h *Handler) SetPostAuthCallback(callback PostAuthCallback)
- func (h *Handler) SetServiceAuthFetcher(fetcher ServiceAuthFetcher)
- type Issuer
- func (i *Issuer) Expiration() time.Duration
- func (i *Issuer) Issue(subject string, access []auth.AccessEntry, authMethod string) (string, error)
- func (i *Issuer) IssueWithExpiration(subject string, access []auth.AccessEntry, authMethod string, ...) (string, error)
- func (i *Issuer) PublicKey() *rsa.PublicKey
- type OAuthSessionValidator
- type PostAuthCallback
- type ServiceAuthFetcher
- type TokenResponse
Constants ¶
const ( AuthMethodOAuth = "oauth" AuthMethodAppPassword = "app_password" )
Auth method constants
Variables ¶
This section is empty.
Functions ¶
func ExtractAccess ¶
func ExtractAccess(tokenString string) []auth.AccessEntry
ExtractAccess parses a JWT token string and extracts the access entries (scopes) Returns nil if not found or token is invalid This does NOT validate the token - it only parses it to extract the claim
func ExtractAuthMethod ¶
ExtractAuthMethod parses a JWT token string and extracts the auth_method claim Returns the auth method or empty string if not found or token is invalid This does NOT validate the token - it only parses it to extract the claim
func ExtractSubject ¶
ExtractSubject parses a JWT token string and extracts the Subject claim (the user's DID) Returns the subject or empty string if not found or token is invalid This does NOT validate the token - it only parses it to extract the claim
func HasPushScope ¶
func HasPushScope(access []auth.AccessEntry) bool
HasPushScope checks if any access entry contains a "push" action
Types ¶
type AuthErrorResponse ¶
type AuthErrorResponse struct {
Error string `json:"error"`
Message string `json:"message"`
LoginURL string `json:"login_url,omitempty"`
}
AuthErrorResponse is returned when authentication fails in a way the credential helper can handle
type Authorizer ¶ added in v0.1.4
type Authorizer interface {
// Authorize is called once per token issuance, after the requester's
// ATProto credentials have been validated. Returns nil if `access` is
// allowed, or an error describing the denial reason. The error message
// surfaces to the OCI client inside the distribution error JSON body.
//
// authMethod is one of AuthMethodOAuth or AuthMethodAppPassword and lets
// the implementation pick the right service-token fetcher when it needs
// to talk to the hold (e.g. for crew reconciliation).
Authorize(ctx context.Context, did, authMethod string, access []auth.AccessEntry) error
}
Authorizer gates issuance of registry JWTs at the auth phase. Implementations decide which sub-checks apply based on `access`: crew reconciliation runs for any token request (so first-time CLI users can pull from a private hold), while membership and quota enforcement only apply to non-wildcard push scopes. The Docker spec model is to embed authorization in the JWT and trust it for its short lifetime; this is the single point where those gates run.
type Claims ¶
type Claims struct {
jwt.RegisteredClaims
Access []auth.AccessEntry `json:"access,omitempty"`
AuthMethod string `json:"auth_method,omitempty"` // "oauth" or "app_password"
}
Claims represents the JWT claims for registry authentication This follows the Docker Registry token specification
type Handler ¶
type Handler struct {
// contains filtered or unexported fields
}
Handler handles /auth/token requests
func NewHandler ¶
func NewHandler(issuer *Issuer, deviceStore *db.DeviceStore) *Handler
NewHandler creates a new token handler
func (*Handler) ServeHTTP ¶
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP handles the token request
func (*Handler) SetAuthorizer ¶ added in v0.1.4
func (h *Handler) SetAuthorizer(authorizer Authorizer)
SetAuthorizer wires the auth-phase gate. When set, every token request runs Authorize after credentials validate; a non-nil error is returned to the client as a 403 (distribution error JSON) and the JWT is not issued.
func (*Handler) SetOAuthSessionValidator ¶
func (h *Handler) SetOAuthSessionValidator(validator OAuthSessionValidator)
SetOAuthSessionValidator sets the OAuth session validator for validating device auth When set, the handler will validate OAuth sessions are usable before issuing tokens for device auth This prevents the flood of errors that occurs when a stale session is discovered during push
func (*Handler) SetPostAuthCallback ¶
func (h *Handler) SetPostAuthCallback(callback PostAuthCallback)
SetPostAuthCallback sets the callback to be invoked after successful Basic Auth authentication This allows AppView to inject business logic without coupling the token package
func (*Handler) SetServiceAuthFetcher ¶ added in v0.1.4
func (h *Handler) SetServiceAuthFetcher(fetcher ServiceAuthFetcher)
SetServiceAuthFetcher binds JWT issuance to the AppView↔hold service-auth. When set, the handler pre-mints the service-auth and stamps the JWT's exp from the cached expiry, so both tokens expire concurrently.
type Issuer ¶
type Issuer struct {
// contains filtered or unexported fields
}
Issuer handles JWT token creation and signing
func NewIssuerFromKey ¶
func NewIssuerFromKey(privateKey *rsa.PrivateKey, certDER []byte, issuer, service string, expiration time.Duration) *Issuer
NewIssuerFromKey creates a JWT issuer from pre-loaded key material. certDER is the DER-encoded X.509 certificate for the x5c JWT header.
func (*Issuer) Expiration ¶
Expiration returns the token expiration duration
func (*Issuer) Issue ¶
func (i *Issuer) Issue(subject string, access []auth.AccessEntry, authMethod string) (string, error)
Issue creates and signs a new JWT token using the issuer's configured expiration.
func (*Issuer) IssueWithExpiration ¶ added in v0.1.4
func (i *Issuer) IssueWithExpiration(subject string, access []auth.AccessEntry, authMethod string, expiration time.Duration) (string, error)
IssueWithExpiration creates and signs a JWT with a per-call expiration. Used when the JWT lifetime is bound to a downstream credential whose lifetime can be slightly less than the issuer's configured default — e.g. the AppView↔hold service-auth, where the cache applies a 10s safety margin against the PDS-granted exp.
type OAuthSessionValidator ¶
type OAuthSessionValidator interface {
// ValidateSession checks if OAuth session is usable by attempting to load/refresh it
// Returns nil if session is valid, error if session is invalid/expired/needs re-auth
ValidateSession(ctx context.Context, did string) error
}
OAuthSessionValidator validates OAuth sessions before issuing tokens This interface allows the token handler to verify OAuth sessions are usable (not just that they exist) without depending directly on the OAuth implementation.
type PostAuthCallback ¶
PostAuthCallback is called after successful Basic Auth authentication. Parameters: ctx, did, handle, pdsEndpoint, accessToken This allows AppView to perform business logic (profile creation, etc.) without coupling the token package to AppView-specific dependencies.
type ServiceAuthFetcher ¶ added in v0.1.4
type ServiceAuthFetcher interface {
// Fetch ensures a service-auth exists for (did, hold derived from did)
// and returns its expiry. Returns (zero time, nil) when the user has no
// hold configured — caller falls back to the issuer's default exp.
Fetch(ctx context.Context, did, authMethod string) (expiresAt time.Time, err error)
}
ServiceAuthFetcher pre-mints the AppView↔hold service-auth at /auth/token time so the registry JWT can be bound to its lifetime. JWT and service-auth then expire concurrently; when Docker hits 401, the next /auth/token call mints both fresh in lockstep.
type TokenResponse ¶
type TokenResponse struct {
Token string `json:"token,omitempty"` // Legacy field
AccessToken string `json:"access_token,omitempty"` // Standard field
ExpiresIn int `json:"expires_in,omitempty"`
IssuedAt string `json:"issued_at,omitempty"`
}
TokenResponse represents the response from /auth/token