auth

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Aug 15, 2026 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Package auth is the mAPI-ng dashboard authentication layer: OIDC login (GitHub/Google, no passwords — CONTEXT Member / roles), HMAC-signed session cookies, and a middleware that gates the dashboard to the caller's org.

It is only wired in when a control plane is present (main.go). Three modes are selected at startup:

  • No control plane: auth is OFF (constant dev tenant, Part 1 behavior).
  • Control plane, no OIDC creds: dev-login only — a button that starts a session as the seeded dev-org admin, for session-gated local testing.
  • Control plane + OIDC creds: real GitHub/Google login; dev-login disabled.

The session is a self-contained HMAC-signed cookie (no server-side store): base64(payload) + "." + base64(hmac-sha256(payload)). The org id in the verified session is what web.Config.Tenant reads, so a member only ever sees their own org's data. Secrets and access tokens are never logged.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func TenantFromContext

func TenantFromContext(r *http.Request) (string, bool)

TenantFromContext returns the authenticated org id for a request, satisfying web's TenantResolver signature shape via the request context. main wires this into web.Config.Tenant, so the dashboard renders only the caller's org.

Types

type Auth

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

Auth is the mAPI-ng dashboard auth layer. It mounts open login routes, verifies session cookies in its Middleware, and exposes TenantFromContext for the web layer's tenant resolver.

func New

func New(cfg Config) (*Auth, error)

New builds the auth layer. Dev-login is enabled ONLY when no real provider is configured, so a production deployment with GitHub/Google never exposes the bypass. Returns an error for a too-short session key.

func (*Auth) Authenticated

func (a *Auth) Authenticated(r *http.Request) bool

Authenticated reports whether the request carries a valid session cookie, without requiring the Middleware to have run. The composition root uses it at "/" to serve the public home to anonymous visitors while routing signed-in users to the dashboard.

func (*Auth) Enabled

func (a *Auth) Enabled() (providers []string, devLogin bool)

Enabled reports the active auth configuration: the enabled provider names and whether dev-login is on. main logs it at startup so the active mode is clear.

func (*Auth) Middleware

func (a *Auth) Middleware(next http.Handler) http.Handler

Middleware verifies the session cookie and, on success, stores the identity in the request context before calling next. On failure it redirects a browser request to /login, or returns 401 JSON for an /api/ path (so htmx/fetch callers get a machine-readable status instead of an HTML redirect body).

func (*Auth) Register

func (a *Auth) Register(mux *http.ServeMux)

Register mounts the OPEN auth routes on mux. None of these sit behind the session gate (a logged-out user must reach the login flow). main mounts the session-gated dashboard separately at "/".

func (*Auth) SetSession

func (a *Auth) SetSession(w http.ResponseWriter, orgID, memberID, role string)

SetSession signs and writes the dashboard session cookie for a resolved member, implementing PostAuthContext so a composed LoginInterceptor can start a session through the same path the core first-login uses.

type Config

type Config struct {
	// Store is the control-plane member store (required).
	Store MemberStore
	// SessionKey signs session cookies (>= 32 bytes required).
	SessionKey []byte
	// Providers holds the per-provider OAuth credentials + base URL.
	Providers ProviderConfig
	// DevOrgName is the seeded dev org used by dev-login (when enabled).
	DevOrgName string
	// Secure sets the Secure cookie flag; main sets it true when the base URL
	// is https.
	Secure bool
	// HTTPClient performs the token exchange and userinfo calls. main supplies
	// one with an explicit timeout.
	HTTPClient *http.Client
	// Logger is the structured logger (defaults to slog.Default()).
	Logger *slog.Logger
	// Interceptor is the composed post-auth hook the callback consults after the
	// identity is verified (nil = plain login).
	Interceptor LoginInterceptor
}

Config bundles the auth layer's dependencies and startup options. main builds it from the environment.

type LoginInterceptor

type LoginInterceptor interface {
	Handle(pa PostAuthContext, w http.ResponseWriter, r *http.Request, oidcSubject, email string) (handled bool)
}

LoginInterceptor is an optional post-authentication hook the OIDC callback consults after the identity is verified, before the default first-login flow. Handle returns true when it fully handled the response (the callback then returns); false falls through to UpsertMemberFromOIDC. pa lets it start a session. A nil interceptor means plain login only.

type MemberStore

type MemberStore interface {
	// UpsertMemberFromOIDC resolves (creating on first login) the member behind
	// an OIDC identity, returning its org id, member id, role, and whether this
	// call created the member (first login) — which triggers the key interstitial.
	UpsertMemberFromOIDC(ctx context.Context, oidcSubject, email string) (orgID, memberID, role string, isNew bool, err error)
	// DevOrgAdmin returns the seeded dev org's admin member, for dev-login.
	DevOrgAdmin(ctx context.Context, devOrgName string) (orgID, memberID string, err error)
	// IssueKey mints an ingest key for an org and returns its plaintext secret
	// once (only the hash is stored). Used to auto-issue the first key at signup.
	IssueKey(ctx context.Context, orgID, label string) (secret string, err error)
}

MemberStore is the control-plane surface the auth layer needs. control.Store satisfies it. Keeping it an interface here means auth never imports control (auth sits above the control plane in the wiring only through main) and the handlers are unit-testable against a fake.

type PostAuthContext

type PostAuthContext interface {
	// SetSession signs and writes the dashboard session cookie for a resolved
	// member, exactly as the core first-login path does.
	SetSession(w http.ResponseWriter, orgID, memberID, role string)
}

PostAuthContext is the capability surface a LoginInterceptor uses to complete a post-authentication flow — today, starting a dashboard session for a member it resolved out of band (e.g. by accepting an invite). It keeps the session signer private to auth while letting a composed feature finish the login.

type ProviderConfig

type ProviderConfig struct {
	GitHubClientID     string
	GitHubClientSecret string
	GoogleClientID     string
	GoogleClientSecret string
	BaseURL            string
}

ProviderConfig is the raw per-provider credential input read from the environment by main and passed to newAuth.

type Session

type Session struct {
	OrgID    string
	MemberID string
	Role     string
	Exp      time.Time
}

Session is the identity carried in the signed cookie. Exp is an absolute expiry; a decoded session past Exp is rejected as logged out.

func FromContext

func FromContext(ctx context.Context) (Session, bool)

FromContext returns the authenticated session stored by the Middleware, or ok=false when the request is unauthenticated.

Jump to

Keyboard shortcuts

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