# Ory Kratos — identity & self-service auth. Identity schema (email, name) + # password login; recovery & verification run on email codes. Every self-service # flow returns to our own themed routes (§4 renders the fields). DSN + prod # courier/secrets come from the env. Session→JWT tokenizer wired below (signing # key in tokenizer/jwks.json). serve: public: base_url: http://127.0.0.1:4433/ cors: enabled: false admin: base_url: http://kratos:4434/ selfservice: default_browser_return_url: http://127.0.0.1:3000/ allowed_return_urls: - http://127.0.0.1:3000 methods: password: enabled: true code: # email one-time code — powers recovery + verification (not login) enabled: true # Social sign-in, OFF by default → clean clone is password-only. Activate via env only # (no code; the whole-array form is the only env-settable one Kratos offers); §4 derives # the buttons from this list. SAML isn't in OSS Kratos — bridge it as OIDC (README). # SELFSERVICE_METHODS_OIDC_ENABLED=true # SELFSERVICE_METHODS_OIDC_CONFIG_PROVIDERS=[{"id":"google","provider":"google", # "client_id":"…","client_secret":"…","scope":["openid","email","profile"], # "mapper_url":"file:///etc/config/kratos/oidc/claims.jsonnet"}] oidc: enabled: false config: providers: [] flows: error: ui_url: http://127.0.0.1:3000/error login: ui_url: http://127.0.0.1:3000/login after: # After authenticating, land on our completion route — it mints the session JWT # (roles from Keto → metadata_public projection → tokenize) and sets our cookie (§4). default_browser_return_url: http://127.0.0.1:3000/auth/complete registration: ui_url: http://127.0.0.1:3000/registration after: password: hooks: - hook: session # log in immediately after sign-up - hook: show_verification_ui settings: ui_url: http://127.0.0.1:3000/settings privileged_session_max_age: 15m required_aal: highest_available recovery: enabled: true use: code ui_url: http://127.0.0.1:3000/recovery verification: enabled: true use: code ui_url: http://127.0.0.1:3000/verification after: default_browser_return_url: http://127.0.0.1:3000/ logout: after: default_browser_return_url: http://127.0.0.1:3000/login # Dev mail catcher (compose.override.yml). Prod overrides via COURIER_SMTP_CONNECTION_URI. courier: smtp: connection_uri: smtp://mailpit:1025/?disable_starttls=true from_address: no-reply@plainpages.local from_name: Plainpages identity: default_schema_id: default schemas: - id: default url: file:///etc/config/kratos/identity.schema.json # "Stay signed in" backbone: a long-lived Kratos session that the app re-mints the # short-lived (~10m) JWT off (§4). Sliding refresh — an active session is extended # back to full lifespan only once it's within earliest_possible_extend of expiry, # so frequent users never lapse without a DB write per request. session: lifespan: 720h # 30 days earliest_possible_extend: 24h cookie: name: plainpages_session persistent: true # survive browser restarts same_site: Lax # Session→JWT tokenizer (§4): whoami(tokenize_as: plainpages) mints a short-lived, # locally-verifiable JWT so the hot path never calls Ory. Claims come from the # committed Jsonnet mapper (sub = identity id, email from traits, roles from the # metadata_public projection); signed with tokenizer/jwks.json. whoami: tokenizer: templates: plainpages: ttl: 10m subject_source: id claims_mapper_url: file:///etc/config/kratos/tokenizer/plainpages.jsonnet jwks_url: file:///etc/config/kratos/tokenizer/jwks.json # Dev throwaways — production supplies real secrets via env (§3). cipher = 32 chars. secrets: cookie: - PLEASE-CHANGE-ME-dev-kratos-cookie-secret cipher: - 0123456789abcdef0123456789abcdef log: level: info format: text