Documentation
¶
Overview ¶
Package browser implements AuthHub relying-party browser sessions using the reviewed OIDC libraries and durable generation fences. It supplies identity proofs, never local user linking or application permissions.
Index ¶
- Variables
- func ReadClientSecret(path, clientID string) (string, error)
- func ReadProtected(path string, limit int64) ([]byte, error)
- func SQLiteSchema() string
- func Schema() string
- func ValidateAuthHubClientConfig(c Config) error
- func ValidateConfig(c Config) error
- func ValidateIssuerEndpoint(issuer, endpoint string) error
- type Binding
- type CallbackOutcome
- type CanonicalIdentifiers
- type Client
- func (c *Client) Begin(w http.ResponseWriter, r *http.Request)
- func (c *Client) Callback(w http.ResponseWriter, r *http.Request)
- func (c *Client) CallbackResult(w http.ResponseWriter, r *http.Request) (CallbackOutcome, error)
- func (c *Client) Check(ctx context.Context, b Binding) (Proof, error)
- func (c *Client) Handler(render func(http.ResponseWriter, *http.Request, View)) http.Handler
- func (c *Client) Logout(w http.ResponseWriter, r *http.Request)
- func (c *Client) LogoutFromHost(w http.ResponseWriter, r *http.Request)
- func (c *Client) RevokeBinding(ctx context.Context, b Binding) error
- func (c *Client) Valid(ctx context.Context, p Proof) error
- func (c *Client) Verify(r *http.Request) (Proof, error)
- type Config
- type Identity
- type MFAEnrollment
- type Option
- func WithAuthHubClientBoundProject() Option
- func WithCallback(value string) Option
- func WithCentralLogoutURL(value string) Option
- func WithClientID(value string) Option
- func WithClientSecret(value string) Option
- func WithCurrentSessionLogoutEndpoint(value string) Option
- func WithEmailScope() Option
- func WithFreshness(value time.Duration) Option
- func WithHTTPSReverseProxy() Option
- func WithIngress(value *ingress.Policy) Option
- func WithIssuer(value string) Option
- func WithIssuerCAFile(value string) Option
- func WithOrigin(value string) Option
- func WithProjectID(value string) Option
- func WithRequiredAMR(value string) Option
- func WithRevocationEndpoint(value string) Option
- func WithStorageKey(value []byte) Option
- func WithStore(value Store) Option
- type Options
- type PostgresStore
- type Proof
- type SQLiteStore
- type Store
- type View
Constants ¶
This section is empty.
Variables ¶
var ErrDenied = errFenced
ErrDenied means this proof/session cannot authorize the current request. Expired, terminal and superseded generations require a new admission.
var ErrRequiredAMR = errors.New("required authentication method not satisfied")
ErrRequiredAMR means the verified proof lacks the required authentication method. It deliberately does not match ErrDenied: a host must show a terminal policy error, not automatically retry login or initiate fresh admission.
var ErrRevocationUnconfirmed = errors.New("local logout committed; central revocation unconfirmed")
ErrRevocationUnconfirmed means local terminal state committed, but central revocation could not be confirmed. Never replay refresh or resurrect a binding.
ErrUnavailable means the boundary could not confirm validity. Fail closed; do not mint or extend a host session. A later request may retry validity, but must never independently replay an OAuth exchange or claimed refresh.
Functions ¶
func ReadClientSecret ¶
ReadClientSecret reads the exact restart-bound maintenance candidate format.
func ReadProtected ¶
ReadProtected loads an explicitly supplied Linux protected file with the reviewed ownership, mode, size and no-symlink checks. It never prints contents.
func SQLiteSchema ¶ added in v0.4.0
func SQLiteSchema() string
SQLiteSchema returns application-owned DDL. Apply it explicitly before construction. Configure durability and busy timeout on the application's connections; this package never changes PRAGMA settings or user_version. Timestamps are signed INTEGER Unix nanoseconds, never floating-point values.
func Schema ¶
func Schema() string
Schema returns the reviewed RP schema. Existing table names are retained for compatibility; isolate each application's rows using its PostgreSQL schema.
func ValidateAuthHubClientConfig ¶ added in v0.2.0
ValidateAuthHubClientConfig checks the same network-free settings for WithAuthHubClientBoundProject. ProjectID must be empty; the issuer must satisfy that option's immutable-client registration contract.
func ValidateConfig ¶
ValidateConfig checks exact origins and identity pins without network access.
func ValidateIssuerEndpoint ¶
ValidateIssuerEndpoint checks an explicit provider endpoint without network access. Validate application identity/origin settings with ValidateConfig too. For an absent optional central logout link, omit this check and its option.
Types ¶
type Binding ¶
type Binding struct {
Reference string `json:"reference"`
Generation int64 `json:"generation"`
LoginGeneration int64 `json:"loginGeneration"`
Deadline time.Time `json:"deadline"`
Issuer string `json:"issuer"`
Subject string `json:"subject"`
ProjectID string `json:"projectId"`
ClientID string `json:"clientId"`
CentralSessionID string `json:"centralSessionId"`
AuthTime int64 `json:"authTime"`
AbsoluteUntil time.Time `json:"absoluteUntil"`
}
Binding is persisted inside a protected host-owned external session after successful admission. Never accept it from browser form/query/header input. The host must preserve the original Deadline unchanged; it is not a TTL. LoginGeneration identifies a local login admission, preserved across refresh. Zero markers from legacy rows/bindings require a fresh sign-in.
type CallbackOutcome ¶ added in v0.5.0
type CallbackOutcome struct {
// contains filtered or unexported fields
}
CallbackOutcome is an immutable, successfully committed callback result. A zero outcome conveys no authority. Its return path was saved with the one-use state/PKCE/browser-bound login, never read from the callback query.
func (CallbackOutcome) Proof ¶ added in v0.5.0
func (o CallbackOutcome) Proof() Proof
Proof returns a copy of the original, fixed-deadline identity snapshot.
func (CallbackOutcome) ReturnPath ¶ added in v0.5.0
func (o CallbackOutcome) ReturnPath() string
ReturnPath returns the exact validated root-relative path saved at Begin.
type CanonicalIdentifiers ¶ added in v0.2.0
type CanonicalIdentifiers struct {
Version int `json:"version"`
Login string `json:"login"`
EmailAlias string `json:"email_alias,omitempty"`
}
CanonicalIdentifiers is an optional AuthHub-specific signed identity claim. Version 1 asserts that Login and EmailAlias come from the issuer's canonical, operator-administered account records, never arbitrary profile metadata. Login is case-sensitive. EmailAlias is lowercase and optional; it is a login alias, NOT proof of mailbox ownership or an email_verified assertion. These are current issuance snapshots, not immutable subject/session pins. Hosts may use them only under an explicit account-linking policy for their trusted issuer. They grant no local role or permission. Issuer/Subject remains the durable identity key; absence must never fall back to profile metadata.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is safe for concurrent HTTP use. The caller owns the database lifetime.
func New ¶
New retains the original AuthHub-profile API and provider-relative logout routes for existing callers. New integrations should use NewWithOptions. New performs bounded OIDC discovery using the configured issuer trust roots.
func NewWithOptions ¶
NewWithOptions validates explicit identity, origin and protected inputs before discovery. It uses a supplied or discovered revocation endpoint, never a guessed provider route. No central logout link is exposed unless configured. Configuration is frozen at construction; only the caller-owned database and an immutable ingress policy are shared. Protocol and session fences are the same as New; this constructor does not imply general OIDC-provider support.
func (*Client) Begin ¶
func (c *Client) Begin(w http.ResponseWriter, r *http.Request)
Begin handles the exact POST /login form using the library CSRF/browser state.
func (*Client) Callback ¶
func (c *Client) Callback(w http.ResponseWriter, r *http.Request)
Callback handles the exact GET /callback. Success installs durable state and redirects; admit the local user on a subsequent Verify, never from query data.
func (*Client) CallbackResult ¶ added in v0.5.0
func (c *Client) CallbackResult(w http.ResponseWriter, r *http.Request) (CallbackOutcome, error)
CallbackResult handles exactly GET /callback using the same ingress, nonce, state, PKCE, durable generation and concurrency protections as Callback. Success returns only after installation and a current durable re-read; it writes security headers but NO success status, body, cookie or redirect. The host then owns success delivery and may perform transactional enrollment. On error the failure HTTP response is ALREADY written; the host must return without writing another response. No outcome may authorize a failed callback. This method never calls Verify or refreshes a previous browser session.
func (*Client) Check ¶
Check validates a previously admitted host-owned binding after restart without network access or refresh. An edited deadline beyond the durable proof cap is rejected. The host must also match the returned issuer/subject to its explicit local user link and recheck its own ACL; this method grants no local roles.
func (*Client) Handler ¶
Handler serves GET /, POST /login, GET /callback and POST /logout. render owns the landing UI, explicit local user resolution and local permissions. Form POSTs must carry View.CSRF. Other application routes can call Verify directly.
func (*Client) Logout ¶
func (c *Client) Logout(w http.ResponseWriter, r *http.Request)
Logout handles the exact POST /logout. Local terminal generation commits before bounded central revocation. Failed confirmation is not a success acknowledgement; the host must still fail closed at its Check/Valid boundary. A stale login returns 409 and preserves the newer cookie. Local termination with unconfirmed remote revoke/decryption returns 503 and clears the cookie. Anonymous/pending logout redirects to /?logout=local-only. The response's X-AuthHub-Logout-Scope is binding-revoked, local-only, or unconfirmed; it never promises issuer-wide logout. Refresh descendants retain the original intent.
func (*Client) LogoutFromHost ¶ added in v0.2.0
func (c *Client) LogoutFromHost(w http.ResponseWriter, r *http.Request)
LogoutFromHost terminates the current browser's RP session after the host has authenticated intentional logout and verified its OWN CSRF token. Never mount this method directly as an unauthenticated handler: Origin is defense in depth, not a substitute for the host's session-bound CSRF check.
Use this only for a native local host session with no saved external binding. For an admitted external session use RevokeBinding with its ORIGINAL binding; re-reading the browser here would turn stale host intent into newer login intent.
The request must be POST with the exact configured Origin and trusted ingress. No library form/CSRF field is required. The browser snapshot is captured once, without Verify, authorization or refresh, and the ordinary Logout terminal generation fence and response scopes apply. A missing cookie or missing row returns 303 local-only without setting a cookie. Malformed/duplicate cookies, invalid ingress/origin and storage errors preserve cookies and fail closed.
func (*Client) RevokeBinding ¶
RevokeBinding is intentional user logout, not session-replacement cleanup. It ends the current generation and refresh descendants of this same login. A subsequent login has a different LoginGeneration and cannot be revoked by this old binding, even when all central identity claims are unchanged. Expired freshness does not cancel logout intent. A strictly newer generation may have tightened AbsoluteUntil during legacy signed-deadline upgrade; that same-lineage descendant remains a permitted logout target. Unknown local commit returns ErrUnavailable; no automatic retry or remote revoke follows it. ErrRevocationUnconfirmed confirms local termination only. Caller must enforce logout request authentication and CSRF protection.
func (*Client) Valid ¶
Valid checks an external session's original proof against current durable state. It never refreshes, extends deadlines or resurrects a terminal session. Refresh generation changes require a newly admitted proof. Central revocation is bounded by the original signed freshness deadline, at most five minutes.
type Config ¶
type Config struct {
Issuer, ClientID, ProjectID, Origin, Callback string
Freshness time.Duration
IssuerCAFile string
Ingress *ingress.Policy
// RequestEmail opts into requesting and validating signed OIDC email claims.
// It does not require email or grant local linking, membership or roles.
RequestEmail bool
}
Config pins the authority, application origin, client and project. Callback is exactly Origin + /callback. Zero Freshness means the reviewed five-minute cap. Ingress must be nil for direct TLS or an explicitly constructed trusted edge.
type Identity ¶
type Identity struct {
// Email is retained only from a signed ID token when email scope is opted in.
// EmailVerified asserts mailbox ownership at issuance, never local authority.
Email string `json:"email,omitempty"`
EmailVerified bool `json:"email_verified,omitempty"`
// AuthHubIdentifiers is only populated from the dedicated, signed claim.
// Profile and standard email/username claims never supply this authority.
AuthHubIdentifiers *CanonicalIdentifiers `json:"authhub_identifiers,omitempty"`
// AMR contains only methods from the current verified signed ID token.
// Enrollment, profile, access-token and prior-token claims never supply it.
AMR []string `json:"amr,omitempty"`
// AuthHubMFA is an advisory issuance snapshot, never authentication strength.
AuthHubMFA *MFAEnrollment `json:"authhub_mfa,omitempty"`
Issuer string `json:"issuer"`
ClientID string `json:"client_id"`
Subject string `json:"subject"`
ProjectID string `json:"project_id"`
SessionID string `json:"sid"`
AuthTime int64 `json:"auth_time"`
IssuedAt time.Time `json:"issued_at"`
FreshUntil time.Time `json:"fresh_until"`
AbsoluteUntil time.Time `json:"absolute_until"`
// SessionExpiresAt is the verified provider deadline, before local caps.
// Zero identifies legacy stored proofs that must refresh before admission.
SessionExpiresAt time.Time `json:"session_expires_at"`
Profile map[string]string `json:"profile,omitempty"`
Project map[string]string `json:"project,omitempty"`
}
Identity contains independently verified OIDC identity claims.
type MFAEnrollment ¶ added in v0.3.0
type MFAEnrollment struct {
Version int `json:"version"`
Enrolled bool `json:"enrolled"`
SetupAvailable bool `json:"setup_available"`
}
MFAEnrollment is the optional signed authhub_mfa issuance snapshot. It is display-only: never use it as MFA proof, admission policy, or a session pin. Only a verified Identity from a currently valid Proof supplies this hint. Recheck through normal session renewal, not polling or a separate refresh. Setup links must use the application's explicitly configured trusted issuer.
func (*MFAEnrollment) UnmarshalJSON ¶ added in v0.3.0
func (v *MFAEnrollment) UnmarshalJSON(raw []byte) error
UnmarshalJSON keeps a malformed stored advisory hint from breaking an otherwise valid legacy identity. Version zero suppresses its projection.
type Option ¶
type Option func(*options)
Option configures a new client. Use the typed With functions; duplicate options, including repeated identical values, and nil options are rejected.
func WithAuthHubClientBoundProject ¶ added in v0.2.0
func WithAuthHubClientBoundProject() Option
WithAuthHubClientBoundProject selects the AuthHub immutable-client profile instead of an explicit WithProjectID pin. Use only when the configured issuer guarantees a client ID belongs permanently to one project and never reuses that ID for another project. The project comes solely from a fully verified signed ID token and remains pinned in each durable proof, refresh and binding. No project is learned from unsigned metadata or cached as a first-login pin. This option is not safe for a generic provider without the same guarantee.
func WithCallback ¶
WithCallback supplies the registered callback, exactly origin plus /callback.
func WithCentralLogoutURL ¶
WithCentralLogoutURL sets an optional browser sign-out landing URL. It must remain on the issuer origin and conveys no guarantee of issuer-wide logout.
func WithClientID ¶
WithClientID supplies the explicitly registered client identifier.
func WithClientSecret ¶
WithClientSecret supplies a protected client secret. It is never logged.
func WithCurrentSessionLogoutEndpoint ¶ added in v0.3.0
WithCurrentSessionLogoutEndpoint opts intentional user logout into AuthHub's token-bound current-session contract. Cleanup still uses ordinary revocation. The endpoint must confirm X-AuthHub-Logout-Scope: current-session; HTTP 200 alone is insufficient. This option does not clear the issuer browser cookie.
func WithEmailScope ¶ added in v0.5.0
func WithEmailScope() Option
WithEmailScope requests the OIDC email scope and retains strictly typed, signed email/email_verified claims in each proof snapshot. Missing or false verification never becomes true. Email is not required; the host must enforce its enrollment policy and must never infer local linking or roles from email. Omit this option to retain the existing scopes and email-claim behavior.
func WithFreshness ¶
WithFreshness sets a cap no greater than five minutes. Zero retains that cap.
func WithHTTPSReverseProxy ¶ added in v0.2.0
func WithHTTPSReverseProxy() Option
WithHTTPSReverseProxy explicitly delegates incoming transport security to the host application's HTTPS-only reverse proxy. The backend HTTP listener must not be publicly reachable or accept requests outside that trusted edge. This option does not verify network isolation, inspect forwarding headers or fabricate TLS state. Exact Host, Origin/CSRF checks and Secure cookies remain enforced, and issuer HTTPS verification is unchanged. Do not combine it with WithIngress; without either option, requests require direct TLS.
func WithIngress ¶
WithIngress selects an immutable verified edge policy. Nil means direct TLS.
func WithIssuer ¶
WithIssuer supplies the exact canonical HTTPS issuer origin.
func WithIssuerCAFile ¶
WithIssuerCAFile selects bounded public PEM trust roots read at construction.
func WithOrigin ¶
WithOrigin supplies the exact application HTTPS origin, distinct from issuer.
func WithProjectID ¶
WithProjectID supplies the nonzero canonical project UUID to pin in tokens.
func WithRequiredAMR ¶ added in v0.6.0
WithRequiredAMR requires the exact case-sensitive authentication method in every verified ID token and durable proof. Missing or malformed AMR fails closed. It does not request step-up, start sign-in, or infer strength from enrollment hints. Omit this option to accept providers without AMR.
func WithRevocationEndpoint ¶
WithRevocationEndpoint explicitly pins the revocation URL and takes precedence over discovery. Without this option, valid revocation discovery is required.
func WithStorageKey ¶
WithStorageKey snapshots exactly 32 raw key bytes when this option is created. Reusing the option gives each construction a separate copy.
type Options ¶
Options supplies protected inputs. New does not log, generate or persist keys. Store is mandatory: there is no in-memory fallback. No customizable token transport or clock is exposed in the consumer API.
type PostgresStore ¶
type PostgresStore struct {
// contains filtered or unexported fields
}
PostgresStore owns no connection pool. The caller owns db and must apply Schema in an application-owned schema before construction. There are no authority/internal imports and no automatic migrations.
func NewPostgresStore ¶
NewPostgresStore fails closed on absent or partial durable schema.
func NewPostgresStoreWithSchema ¶ added in v0.2.0
func NewPostgresStoreWithSchema(ctx context.Context, db *sql.DB, schemaName string) (*PostgresStore, error)
NewPostgresStoreWithSchema borrows the caller's existing pool and qualifies every session query with schemaName. The schema must already be migrated; construction never opens/closes a pool or changes connection search_path. Names are case-sensitive ASCII identifiers of at most 63 bytes.
type Proof ¶
type Proof struct {
// contains filtered or unexported fields
}
Proof is an immutable snapshot minted by Client.Verify or Handler. Copying a proof preserves its original deadline. Call Valid at each external session admission/validity boundary; do not turn Deadline into a rolling local TTL. The reference is opaque app-owned durable state, not the central OIDC sid.
func (Proof) Binding ¶
Binding returns the durable reference, exact generation and immutable deadline.
func (Proof) Deadline ¶
Deadline returns the fixed minimum of verified freshness and absolute lifetime.
func (Proof) Generation ¶
Generation returns the exact durable generation checked for this proof.
func (Proof) Identity ¶
Identity returns a copy of verified claims. Metadata is display-only, never ACL.
func (Proof) SessionReference ¶
SessionReference returns the nonsecret durable browser-session reference.
type SQLiteStore ¶ added in v0.4.0
type SQLiteStore struct {
// contains filtered or unexported fields
}
SQLiteStore borrows an application-owned SQLite database. It never opens, closes, migrates or changes PRAGMA settings on that database.
func NewSQLiteStore ¶ added in v0.4.0
NewSQLiteStore validates existing tables without migrating or owning db. SQLite 3.35 or newer is required for UPDATE RETURNING.
type Store ¶ added in v0.4.0
type Store interface {
// contains filtered or unexported methods
}
Store is a durable session store constructed by this package. Its private method deliberately prevents custom implementations from bypassing the session transition protocol. The application owns the database lifetime.
type View ¶
type View struct {
CSRF string
Proof *Proof
// CentralLogout is empty unless an explicit central sign-out URL was set.
// Renderers must omit the link when it is empty. Legacy New retains its route.
CentralLogout string
}
View is supplied to application-owned rendering after browser/session checks. A nil Proof conveys no authenticated identity, including outage recovery pages.