Help us shape the future of Go! Take the 2026 Go Developer Survey

kratos

package module
v0.0.28 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: MIT Imports: 26 Imported by: 0

README

backplane-kratos

Ory Kratos joined to a Backplane installation. Kratos stays a stock installation (official image, official chart); this service sits next to it and turns it into parts of Wiring:

  • Kratos's courier → hook kratos.Deliver. Verification, recovery and login codes go wherever the installation binds the hook — typically templates.Render → courier.SendMail or courier.SendSms. A failed delivery is retried by Kratos's own queue.
  • Self-service flows → hooks kratos.Before<Flow> / kratos.After<Flow> (registration, login, settings, recovery, verification). A binding can let the flow continue, deny it with messages on the form, or — after registration and settings — replace traits and metadata. A Before<Flow> hook runs before Kratos creates the flow, so there is no form yet: a deny there makes the flow's creation fail with an error (Kratos answers it as a server error), not form messages. To refuse a step with messages the user sees, deny at After<Flow>. kratos.AfterRegistration runs before Kratos stores the identity, so its req.identity has no id yet. req.session is the acting session as Kratos sends it — id, active, authenticator_assurance_level, authenticated_at, issued_at, expires_at, authentication_methods (method, aal, provider, completed_at) and devices — with no token or cookie: at kratos.BeforeSettings/AfterSettings the signed-in session, so a binding can refuse a settings change for a session the product does not trust (by req.session.id) or one without a second factor; after login and registration the new session, whose id is empty because Kratos stores it only after the hooks.
  • Stored registration → hook kratos.AfterRegistrationStored. Kratos calls it after it stores the identity and waits for the answer. req.identity.id is final, so it is the place to record anything keyed by the new identity (e.g. legal evidence). An error or a denial fails the flow, but the identity stays stored.
  • Completed flows → events Registered, LoggedIn, SettingsChanged, Recovered, Verified for rules and reactors. Kratos runs its after-login hooks before it stores the session, so LoggedIn waits until the session is stored and carries it (id, authenticated_at, AAL, address, user agent); a login whose session is never stored publishes nothing. A registration that signs the identity in (setting Sign the new identity in) publishes Registered the same way, with the session the registration issued; one that does not sign in publishes it at once, without a session. Every flow event carries the flow's transient_payload, the same one its Deliver saw: Kratos gives a courier message no flow id, so a client marker in the payload is how a message and its completed flow are matched.
  • Section kratos.login (backplane live section): how identities sign up and sign in — registration on or off, first and second factors, OIDC providers (id, kind, label), required AALs, recovery and verification — following the console settings, without secrets. Services follow it with sections.Follow[*kratoseventsv1.LoginSection](root, "kratos.login").
  • Admin API → activities: GetIdentity, FindIdentities, CreateIdentity, UpdateIdentity, PatchIdentity, DeleteIdentity, DeleteCredentials, ListSessions, RevokeSessions, ExtendSession, CheckSession, GetSession, CreateRecoveryCode, ListMessages, ImportIdentities; changes publish IdentityCreated/Updated/Deleted and SessionsRevoked.
  • Event contract: the payloads are proto messages in proto/kratos/events/v1 (Go: github.com/backplane-labs/backplane-kratos/proto/kratos/events/v1), in protojson with proto field names: FlowEvent, IdentityEvent, SessionsRevoked. TypeScript (protobuf-es v2): the npm package @backplane-labs/kratos-events, released with the service.
  • Readiness without Kratos: Kratos calls this service (webhooks), so the service is ready without it; Kratos's admin API is probed for the console's health only. Kratos can depend on it with service_healthy.
  • Console module: Kratos's state and every hook point, identities (traits editor checked against the identity schema, credentials, verified addresses, sessions with extend and revoke, recovery codes and links), a batch import, sessions, the courier's queue, identity schemas, and a Settings page that saves revisions of this service's configuration. Every operator change is application audit.
  • Settings from the console: flows on/off (registration included), UI URLs, lifespans, methods (password, codes, passkeys, WebAuthn, TOTP, social sign-in), sessions, identity schemas, the Hydra login provider — live.

How Kratos picks up the settings

Kratos reloads configuration files, nothing else. Kratos runs with two files: the deployment's own and an overlay this service writes:

kratos serve -c /etc/config/kratos.yml -c /etc/backplane/kratos.yml

A key in the overlay wins over the deployment's; lists (hooks) are replaced. The overlay owns the self-service flows and methods, sessions, the courier while kratos.Deliver is bound, identity schemas when the settings define some, and oauth2_provider when set. The deployment keeps dsn, serve, secrets, log and everything the settings do not model (or set it through settings.overrides).

Hook points are written only for bound hooks: binding kratos.AfterLogin in Wiring adds its webhook to the overlay within seconds; an unbound point costs Kratos nothing.

The overlay lives on a volume shared with the Kratos container — run this service as a sidecar. deployments/examples/helm-values.yaml does that with the official chart (a native sidecar: Kratos starts once the overlay is written). Without a shared file (overlay empty) the console shows the rendered configuration to paste instead.

The file holds client secrets: keep it on a pod-private in-memory volume. overlay_mode (default 0644) must let Kratos's user read it; a file Kratos cannot read leaves it on the previous configuration.

Configuration

Key
kratos.admin_url, kratos.public_url Kratos's APIs (default 127.0.0.1:4434/4433)
kratos.headers Secret headers of every request (a proxy's authorization)
callbacks.listen, callbacks.url Where Kratos calls this service (default :8090, http://127.0.0.1:8090)
callbacks.key Authenticates Kratos; default: derived from the internal secret
overlay, overlay_mode The overlay file and its permissions
settings Live: the Kratos settings above, edited on the module's Settings page
oidc_secrets, oauth2_provider_headers Live secrets kept apart from the settings: the console writes them only when an operator enters new ones
fail_open Live: flow hooks whose failure lets the flow continue (default: none — a failing hook stops the flow)

Who made a request: session tokens and pkg/auth

A service learns who made a request without a user cache, so every replica answers alike:

  • Session tokens (the default way). Generate a signing key on the Settings page (Session tokens): Kratos then turns a session into a short JWT at GET <Kratos public>/sessions/whoami?tokenize_as=backplane, and this service serves the public keys at <its public URL>/.well-known/jwks.json. A client sends the token as Authorization: Bearer; a service verifies it locally — no call per request. A revoked session gets no new token at once; a token already issued stays valid for the token lifetime (default 5m).
  • whoami. The session cookie or session token itself, asked of Kratos on every request — no cache: a revocation shows on the next request. For the few actions that must not outlive a revocation.
tokens, _ := auth.NewTokens(auth.TokensOptions{
	KeysURL: "http://backplane-kratos/.well-known/jwks.json",
	Issuer:  "https://auth.example.com/", // Kratos's serve.public.base_url
})
sessions, _ := auth.NewSessions("http://kratos:4433", nil)
a := auth.Authenticator{Tokens: tokens, Sessions: sessions}

mux.Handle("/api/", a.Required(api)) // a bearer JWT, a session token or Kratos's cookie
// in a handler:
who, _ := auth.FromContext(r.Context()) // who.IdentityID, who.HasRole("operator"), who.AtLeast(auth.AAL2)

Roles are the roles list of the identity's public metadata. The token's claims come from Jsonnet (Settings → Session tokens → Claims): by default aal, amr, authenticated_at, email, schema_id and metadata, next to Kratos's iss, sub, sid, iat, nbf, exp, jti.

Rotating the key: generate a new one on the same page and save; the earlier public key stays listed so the tokens it signed keep verifying, and is removed after a token lifetime. The only cache in pkg/auth is of these public keys: fetched on first use, again on a token with an unknown kid (at most once per 30s) and in the background every 10m; when the keys cannot be fetched, the last good set keeps verifying.

Example wiring

Kratos's messages through the installation's templates and courier:

hook: kratos.Deliver
steps:
  rendered:
    activity: templates.Render
    input: {template: "'kratos.' + req.template_type", data: {code: req.code, link: req.link}}
  mail:
    activity: courier.SendMail
    when: req.channel == 'email'
    input: {to: [req.recipient], subject: rendered.parts.subject, text: rendered.parts.text, html: rendered.parts.html}
  sms:
    activity: courier.SendSms
    when: req.channel == 'sms'
    input: {to: req.recipient, text: rendered.parts.text}
result: {}

Codes by SMS: give a trait "format": "tel" and "via": "sms" in the identity schema (credentials code, verification, recovery); Kratos sends those codes on the sms channel of the same hook, req.channel == 'sms', req.recipient the phone in E.164. Recovery by SMS needs the setting Choose the recovery address. courier delivers SMS through a provider plugin (courier.SendSms).

A registration policy in CEL alone:

hook: kratos.AfterRegistration
steps: {}
result:
  deny: "req.identity.traits.email.endsWith('@example.org') ? dyn({'messages': [{'field': 'traits.email', 'id': 4000100, 'text': 'Use your work address'}]}) : dyn(null)"

Develop

make configure configure-web   # tools into ./bin, web dependencies
make gen web build             # protos, console module, binary
make test                      # unit tests
make it-up it                  # integration tests against a real Kratos (docker)

Kratos v26.2.0; the overlay is validated against its configuration schema before it is written.

Documentation

Overview

Package kratos is backplane-kratos as a library: Main runs it. It joins an Ory Kratos installation to Backplane: the courier's messages and the self-service flows become hooks and events, the admin API becomes activities and a console module, and the settings an operator edits are written to a configuration overlay Kratos reloads.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoKey = errors.New("kratos: callbacks.key or backplane.internal_secret is required")

ErrNoKey: neither a callbacks key nor an internal secret is configured.

View Source
var ErrOverlayMode = errors.New("kratos: overlay_mode must be octal permission bits like 0640")

ErrOverlayMode: overlay_mode is not octal permission bits.

Functions

func Main

func Main()

Main runs backplane-kratos until a signal stops it, exiting on error.

func Run

func Run(ctx context.Context) error

Run runs backplane-kratos until ctx ends or a signal stops it.

Types

type Callbacks

type Callbacks struct {
	Listen string `json:"listen" schemapb:"default=:8090"`
	// URL is the listener as Kratos reaches it.
	URL string `json:"url" schemapb:"default=http://127.0.0.1:8090"`
	// Key authenticates Kratos; empty: derived from the internal secret,
	// the same on every replica.
	Key config.Secret `json:"key,omitempty"`
}

Callbacks listener.

type Config

type Config struct {
	config.Backplane `json:"backplane"`

	// Kratos is the installation.
	Kratos Connection `json:"kratos"`
	// Callbacks is the listener Kratos calls (courier, hooks, events).
	Callbacks Callbacks `json:"callbacks"`
	// Overlay is the file Kratos loads after its own (-c base -c overlay),
	// shared with the Kratos container; empty: nothing is written, the
	// console shows the configuration to paste.
	Overlay string `json:"overlay,omitempty" schemapb:"description=Path of the overlay file Kratos loads (empty: snippets only)"`
	// OverlayMode is the file's permission bits (octal): Kratos's user
	// must read it.
	OverlayMode string `json:"overlay_mode,omitempty" schemapb:"default=0644"`
	// Settings are Kratos's settings rendered into the overlay; live.
	Settings config.Live[overlay.Settings] `json:"settings"`
	// OIDCSecrets are the OIDC providers' client secrets by provider id;
	// live, kept apart from the settings.
	OIDCSecrets config.Live[map[string]config.Secret] `json:"oidc_secrets,omitempty" schemapb:"description=Client secrets of the OIDC providers by provider id"`
	// OAuth2ProviderHeaders go with Kratos's requests to Hydra; live.
	OAuth2ProviderHeaders config.Live[map[string]config.Secret] `json:"oauth2_provider_headers,omitempty" schemapb:"description=Headers of Kratos's requests to Hydra's admin API"`
	// TokenKey is the private JWK (JSON) session tokens are signed with; its
	// public key must be the first of settings.tokens.keys. Live, a secret.
	TokenKey config.Live[config.Secret] `json:"token_key,omitempty" schemapb:"description=Private JWK the session tokens are signed with (empty: no tokens)"`
	// FailOpen names flow hooks whose failure lets the flow continue.
	FailOpen config.Live[[]string] `json:"fail_open,omitempty" schemapb:"description=Flow hooks (e.g. AfterLogin) whose failure lets the flow continue"`
}

Config is the whole configuration: file (BACKPLANE_CONFIG_FILE) < env KRATOS_* (BACKPLANE_* for the SDK block) < Consul KV for Live fields.

func (*Config) Validate

func (c *Config) Validate() error

Validate what the schema cannot: the settings must render into a configuration Kratos accepts.

type Connection

type Connection struct {
	AdminURL  string                   `json:"admin_url"         schemapb:"default=http://127.0.0.1:4434"`
	PublicURL string                   `json:"public_url"        schemapb:"default=http://127.0.0.1:4433"`
	Headers   map[string]config.Secret `json:"headers,omitempty" schemapb:"description=Headers of every request (a proxy's authorization)"`
	Timeout   time.Duration            `json:"timeout"           schemapb:"default=10s"`
}

Connection to Kratos.

type State

type State struct {
	// Kratos is the installation, probed for the console's health but not
	// part of readiness: Kratos calls this service (webhooks), so it starts
	// after it is ready.
	Kratos     deps.Optional[ory.Client]
	Flows      *flows.Flows
	Applier    *apply.Applier
	Activities *activities.Activities
	Admin      *admin.Admin
	// contains filtered or unexported fields
}

State is the service's tree.

Directories

Path Synopsis
cmd
kratos command
Command kratos runs backplane-kratos.
Command kratos runs backplane-kratos.
internal
activities
Package activities offers Kratos's admin API to wiring: identities, credentials, sessions, recovery and the courier's queue.
Package activities offers Kratos's admin API to wiring: identities, credentials, sessions, recovery and the courier's queue.
admin
Package admin is the console module's API: the Kratos installation, its identities, sessions and courier, and the overlay.
Package admin is the console module's API: the Kratos installation, its identities, sessions and courier, and the overlay.
apply
Package apply keeps the overlay file equal to the settings and the bound hooks: rendered at start, after every settings change and every binding change, and every resync interval (a file someone replaced).
Package apply keeps the overlay file equal to the settings and the bound hooks: rendered at start, after every settings change and every binding change, and every resync interval (a file someone replaced).
events
Package events builds the payloads of backplane-kratos's events, whose contract is proto/kratos/events/v1.
Package events builds the payloads of backplane-kratos's events, whose contract is proto/kratos/events/v1.
flows
Package flows turns Kratos's callbacks into Backplane hooks and events: the courier's messages (hook Deliver), the before/after points of the self-service flows (hooks Before<Flow>/After<Flow>) and the facts of completed flows (events).
Package flows turns Kratos's callbacks into Backplane hooks and events: the courier's messages (hook Deliver), the before/after points of the self-service flows (hooks Before<Flow>/After<Flow>) and the facts of completed flows (events).
insight
Package insight finds settings that Kratos's schema accepts but that do not work together: a flow without its UI, links without the link method, codes with nowhere to go, nobody able to sign in.
Package insight finds settings that Kratos's schema accepts but that do not work together: a flow without its UI, links without the link method, codes with nowhere to go, nobody able to sign in.
jwks
Package jwks serves the session tokens' public keys: services verify a token's signature with them (pkg/auth).
Package jwks serves the session tokens' public keys: services verify a token's signature with them (pkg/auth).
ory
Package ory is a small client of an Ory Kratos installation: the admin API (identities, sessions, recovery, courier messages) and the parts of the public API an operator needs (identity schemas, whoami).
Package ory is a small client of an Ory Kratos installation: the admin API (identities, sessions, recovery, courier messages) and the parts of the public API an operator needs (identity schemas, whoami).
overlay
Package overlay renders the Kratos configuration file backplane-kratos owns: the settings an operator edits in the console and the callbacks of bound hooks.
Package overlay renders the Kratos configuration file backplane-kratos owns: the settings an operator edits in the console and the callbacks of bound hooks.
ui
Package ui carries the console module: web/dist/plugin copied here by `make web` and embedded into the binary.
Package ui carries the console module: web/dist/plugin copied here by `make web` and embedded into the binary.
pkg
auth
Package auth tells a service who made a request, from the credentials Ory Kratos gives a signed-in user.
Package auth tells a service who made a request, from the credentials Ory Kratos gives a signed-in user.
proto

Jump to

Keyboard shortcuts

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