auth

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 14, 2026 License: Apache-2.0 Imports: 43 Imported by: 0

Documentation

Overview

Package auth authenticates requests (SPEC §8): browser sessions via the built-in OIDC login (Okta, Entra ID, Google…), identity-aware proxies (Google IAP, AWS ALB OIDC, trusted headers), Backyard API tokens, static tokens and IdP-issued bearer JWTs (device flow). In mode "none" everyone is an anonymous guest identified by a cookie.

Index

Constants

View Source
const (
	ModeNone   = "none"
	ModeOIDC   = "oidc"
	ModeIAP    = "iap"
	ModeALB    = "alb"
	ModeHeader = "header"
)

Normalized auth modes.

View Source
const (
	PathPrefix   = "/__backyard/auth/"
	LoginPath    = PathPrefix + "login"
	CallbackPath = PathPrefix + "callback"
	LogoutPath   = PathPrefix + "logout"
	CLIPath      = PathPrefix + "cli"
)

Paths served by Handler.

View Source
const (
	SessionCookie = "backyard_session"
	// OAuthCookie holds the login state when server.public_url is http.
	OAuthCookie = "backyard_oauth"
	// OAuthHostCookie holds the login state when server.public_url is https:
	// browsers accept a "__Host-" cookie only from the host itself (Secure,
	// Path=/, no Domain), so a site's page cannot plant one on the hub.
	OAuthHostCookie = "__Host-" + OAuthCookie
	AnonCookie      = "backyard_anon"
)

Cookie names.

View Source
const (
	// IAPHeader carries the signed IAP assertion.
	IAPHeader = "X-Goog-IAP-JWT-Assertion"
	// IAPIssuer is the "iss" of IAP assertions.
	IAPIssuer = "https://cloud.google.com/iap"
	// DefaultIAPJWKSURL publishes IAP's ES256 signing keys.
	DefaultIAPJWKSURL = "https://www.gstatic.com/iap/verify/public_key-jwk"
)
View Source
const (
	// TokenIssuer is the "iss" claim of Backyard API tokens.
	TokenIssuer = "backyard"
	// TokenScope is the "scope" claim of Backyard API tokens.
	TokenScope = "api"
	// DefaultTokenTTL is used when NewTokens is given a non-positive TTL.
	DefaultTokenTTL = 720 * time.Hour
)
View Source
const (
	// ALBHeader carries the ALB-signed user claims.
	ALBHeader = "X-Amzn-Oidc-Data"
)

Variables

View Source
var (
	// ErrUnauthenticated: no (valid) credentials were presented.
	ErrUnauthenticated = errors.New("auth: unauthenticated")
	// ErrForbidden: authenticated but not allowed (domain/group gate).
	ErrForbidden = errors.New("auth: forbidden")
	// ErrCookieConflict: the browser sent valid session (or guest) cookies
	// of different users, e.g. one planted by a site's page. It is always
	// wrapped together with ErrUnauthenticated.
	ErrCookieConflict = errors.New("auth: the browser sent sign-in cookies of different users")
)

Functions

This section is empty.

Types

type Authenticator

type Authenticator interface {
	Authenticate(w http.ResponseWriter, r *http.Request) (*identity.User, error)
	// LoginURL returns the URL a browser should be redirected to in order to
	// log in and come back to returnTo, or "" when interactive login is not
	// handled by Backyard (iap/alb/header/none).
	LoginURL(returnTo string) string
	// Handler serves /__backyard/auth/* on the hub host (login, callback,
	// logout, cli). It expects the full request path.
	Handler() http.Handler
	// Mode returns the normalized auth mode.
	Mode() string
}

Authenticator resolves the user behind a request.

Authenticate returns (user, nil) on success, (nil, ErrUnauthenticated) when the request carries no usable credentials, (nil, ErrForbidden) when the user is authenticated but rejected by allowed_domains/allowed_groups, or another error for infrastructure failures. Bearer tokens (API, static, IdP JWT) are accepted in every mode. In mode "none" Authenticate only fails when an invalid bearer token is presented, or when the browser sends valid guest cookies of different guests (ErrUnauthenticated, with ErrCookieConflict); otherwise it returns an anonymous user and, when w is non-nil, sets the backyard_anon cookie. On a cookie conflict Authenticate expires the cookies Backyard did not set itself when w is non-nil.

func New

func New(ctx context.Context, cfg *config.Config, opts Options) (Authenticator, error)

New builds the authenticator for cfg.Auth.Mode. For mode "oidc" it performs OIDC discovery against the issuer (ctx bounds that call).

HTTPClient defaults to a client with a 15 s timeout (a client without a timeout gets one). When auth.oidc.issuer is configured in a mode other than oidc (device flow behind a proxy), discovery for IdP bearer tokens is attempted here and, if the IdP is unreachable, retried lazily.

func NewBearer

func NewBearer(ctx context.Context, cfg *config.Config, opts Options) (Authenticator, error)

NewBearer builds a bearer-only authenticator for the standalone deploy gateway: it accepts Backyard API tokens, static tokens and (if cfg.Auth.OIDC.Issuer is set) IdP-issued JWTs — never cookies or proxy headers. Handler() serves nothing and LoginURL returns "".

IdP discovery is attempted here but never fails construction: when the IdP is unreachable it is retried lazily when the first IdP token arrives.

type Options

type Options struct {
	// Directory enriches users after claim mapping (optional).
	Directory identity.Directory
	// HTTPClient is used for OIDC discovery and JWKS/key fetches (default: a
	// client with a 15 s timeout; a client without a timeout gets one).
	HTTPClient *http.Client
	// Logger (default slog.Default()).
	Logger *slog.Logger
	// Now overrides the clock (tests).
	Now func() time.Time
}

Options are optional dependencies for authenticators.

type TokenClaims

type TokenClaims struct {
	Subject string   `json:"sub"`
	Email   string   `json:"email,omitempty"`
	Name    string   `json:"name,omitempty"`
	Groups  []string `json:"groups,omitempty"`
	Admin   bool     `json:"admin,omitempty"`
	Scope   string   `json:"scope"`
}

TokenClaims are the claims of a Backyard API token (SPEC §8.3).

type Tokens

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

Tokens mints and verifies Backyard API tokens (SPEC §8.3).

Tokens are HS256 JWTs keyed with keys.Derive(server.secret, keys.APIToken) carrying {iss:"backyard", sub, email, name, groups, admin, scope:"api", jti, iat, exp}. Rotating server.secret revokes every token. A Tokens value is immutable and safe for concurrent use.

func NewTokens

func NewTokens(secret string, defaultTTL time.Duration) *Tokens

NewTokens returns a token issuer/verifier keyed from secret.

func (*Tokens) Issue

func (t *Tokens) Issue(u *identity.User, ttl time.Duration) (token string, expiresAt time.Time, err error)

Issue mints a token for u with scope "api". ttl <= 0 uses the default TTL.

The token always fits the size Verify accepts: an overlong name is shortened and, if needed, trailing groups are dropped (callers that care which groups survive put the important ones first).

func (*Tokens) Verify

func (t *Tokens) Verify(token string) (*identity.User, error)

Verify validates a token and returns the user it represents.

Only HS256 is accepted (no "none", no asymmetric algorithms); iss must be "backyard", scope "api", and exp/iat are checked with 30 seconds of leeway. Errors wrap ErrUnauthenticated. The returned user carries Admin as recorded in the token; subjects starting with "anon:" are anonymous.

Jump to

Keyboard shortcuts

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