iammiddleware

package
v1.48.3 Latest Latest
Warning

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

Go to latest
Published: Jul 16, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package iammiddleware is the gateway-trust shim for legacy call sites. It used to do JWKS fetch + JWT validation in-binary (293 LOC). That trust boundary is now hanzoai/gateway: gateway validates the JWT, populates X-Org-Id / X-User-Id / X-User-Email, and only gateway-routed traffic reaches commerced.

This file preserves the public API the rest of commerce depends on (Init, InitKV, Client, IAMTokenRequired, IsIAMAuthenticated, GetIAMClaims, GetIAMTier) so the 13 call sites compile, but every function reads identity from the gateway-supplied headers via pkg/auth.

Deletion target: once all call sites migrate to pkg/auth + pkg/org, this file can be removed wholesale.

Index

Constants

View Source
const HeaderRoles = "X-Roles"

HeaderRoles is the canonical comma-joined role-name header set by the gateway from the JWT roles claim. Empty value -> no roles.

View Source
const HeaderTest = "X-Hanzo-Test"

HeaderTest is the gateway-propagated test-mode signal. When the gateway forwards "true" (only for test orgs), the request runs in TEST mode: org.Live=false, charges hit sandbox processors, ledger rows are flagged Test. Absent/any-other value ⇒ live. Mirrors the X-Hanzo-Test semantics in middleware/accesstoken.go. The gateway is the trust boundary; commerced trusts the bit it forwards.

View Source
const HeaderUserIsAdmin = "X-User-IsAdmin"

HeaderUserIsAdmin is the gateway-minted "true"/"" ORG-level admin flag (set for an org owner). Only "true" (case-insensitive) is treated as admin; any other value (including absent) fails closed to false. It is org-scoped only — NEVER gate cross-org/superadmin actions on it; use IsSuperAdmin().

View Source
const HeaderUserOwner = "X-User-Owner"

HeaderUserOwner is the gateway/EdgeAuth-minted HOME-org header — the validated JWT `owner`, the identity + platform-sudo anchor. DISTINCT from X-Org-Id (the EFFECTIVE org a SuperAdmin can switch to another tenant): IsSuperAdmin gates on this so owner=="admin" survives an org-switch. Replaces the removed X-User-IsGlobalAdmin boolean — the org IS the signal, not a spoofable flag.

View Source
const HeaderUserPermissions = "X-User-Permissions"

HeaderUserPermissions is the canonical gateway-minted permission header. It carries the bit.Field value as a base-10 int64 string (e.g. "3" for Live|Test). The gateway MUST set it from the validated JWT roles/claims; commerced reads it as-is. Missing or malformed values fail closed (zero permissions). Documented in HEADERS.md.

Variables

This section is empty.

Functions

func Client added in v1.39.1

func Client() *auth.IAMClient

Client returns the initialized IAM client, or nil if IAM is disabled or Init() has not been called. Consumers outside the middleware chain (e.g. SPA handlers with their own auth gate) use this to validate bearer tokens against the same JWKS the /v1 middleware uses. Fail-closed: a nil return means "treat every request as unauthenticated".

Returns the client built by Init from the IAM config, or nil when IAM is disabled / misconfigured (fail-closed at the call site). This is the non-gateway entry point hook: commerce-api.hanzo.ai is exposed directly (not behind hanzoai/gateway), so its edge surfaces verify the JWT here.

func GetIAMClaims

func GetIAMClaims(c *zip.Ctx) *auth.IAMClaims

GetIAMClaims returns a non-nil *auth.IAMClaims populated from the gateway-minted identity headers. The gateway validated the JWT and stamped X-Org-Id, X-User-Id, X-User-Email, X-User-IsAdmin, X-Roles (see hanzoai/gateway/auth_middleware.go). commerced trusts those bits and reflects them into a claims struct so call sites can read IsAdmin / Owner / Subject / Roles uniformly.

Fail-closed contract: missing headers map to zero-valued fields. In particular, missing X-User-IsAdmin yields IsAdmin=false (not "unknown"). Call sites MUST NOT nil-guard the return — it is always non-nil.

The legacy in-test path stores a *auth.IAMClaims under the "iam_claims" local; that wins when present so tests can inject arbitrary claim shapes without going through HTTP.

func GetIAMTier added in v1.36.4

func GetIAMTier(_ *zip.Ctx) string

GetIAMTier returns "" — tier is no longer derived in-binary. The gateway can attach an X-Tier header in a future iteration if needed.

func IAMTokenRequired

func IAMTokenRequired() zip.Handler

IAMTokenRequired returns a zip middleware that:

  1. Reads the gateway-supplied X-Org-Id / X-User-Id / X-User-Email headers (already JWT-validated upstream).
  2. Resolves the Organization via pkg/org.Resolve (KV-cached).
  3. Sets the legacy context keys downstream handlers expect: iam_authenticated, iam_org, iam_user_id, iam_email, organization, active-organization, permissions.

Missing headers: falls through (handler chain may use a legacy org-token instead). The gateway is the trust boundary; commerced is only reachable via the gateway in production, where COMMERCED_REQUIRE_IDENTITY rejects header-less requests at the edge of the binary.

func Init

func Init(cfg *auth.IAMConfig) error

Init builds the IAM client used by the directly-exposed commerce-api edge — the surfaces that face a raw user Bearer JWT instead of gateway-minted headers: EdgeAuth (middleware/edgeauth.go) and the /admin/billing UI gate (billing/handler.go). It verifies tokens against the IAM JWKS. The gateway-trust middleware chain (IAMTokenRequired) is unchanged — it still reads validated headers.

A nil config or a build error leaves the client nil, so those edge surfaces fail closed (every request treated as unauthorized).

func InitKV added in v1.36.4

func InitKV(kv KVCache)

InitKV wires the KV cache used by org-id resolution.

func IsIAMAuthenticated

func IsIAMAuthenticated(c *zip.Ctx) bool

IsIAMAuthenticated reports whether a VALIDATED IAM identity is attached to the request — i.e. IAMTokenRequired resolved the org from the trusted (gateway- or EdgeAuth-minted, post-strip) X-Org-Id and set iam_authenticated. It does NOT fall back to the raw X-Org-Id header: trusting mere header presence let an unvalidated opaque bearer + a client X-Org-Id impersonate any org (the checkout money-surface bypass). IAMTokenRequired runs on every /v1, /v1/commerce and /_/commerce group, so the local-key check covers every legitimate IAM caller; an opaque service token authorizes through TokenRequired's service-token branch instead, never here.

Types

type KVCache added in v1.36.4

type KVCache = org.KVCache

KVCache mirrors the pkg/org KVCache interface so existing wiring (commerce.go: iammiddleware.InitKV(kv)) keeps working unchanged.

Jump to

Keyboard shortcuts

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