← All posts
    cli · yaml · config-as-code

    Auth as code: one YAML, every environment

    Rodrigo Vidal
    Rodrigo VidalApril 28, 2026 · 5 min read

    Most auth dashboards are time machines pointed at a worse era of operations: click around, hope you remembered which environment you're in, screenshot the result for the audit log. Drift between staging and prod is the default. Onboarding a new engineer is "let me share my screen."

    We built the CLI before we built the dashboard for exactly this reason. Authaz is configured by a single YAML file, applied with one command, and protected by an ETag so two engineers can't trample each other's changes.

    The schema is real

    The YAML below is the actual schema validated by Authaz.Cli. apiVersion: authaz/v1 and kind: Application are required. The shape mirrors Kubernetes manifests on purpose — engineers already know how to read these.

    authaz.yaml
    apiVersion: authaz/v1
    kind: Application
    metadata:
      name: acme
      etag: "5f3a2b1c"
    spec:
      authentication:
        providers:
          emailPassword:
            enabled: true
            minLength: 12
            rejectBreached: true
          magicLink:
            enabled: true
            codeType: numeric
            codeLength: 6
            codeExpiryMinutes: 15
          oauth:
            - provider: google
              scopes: [openid, profile, email]
        mfa:
          mode: required
          allowedMethods: [totp, webauthn]
          primaryMethod: totp
          gracePeriodDays: 7
          requireForAdmins: true
        session:
          timeoutMinutes: 480
          idleTimeoutMinutes: 30
          maxConcurrentSessions: 5
      branding:
        preset: professional
    $ authaz apply --file authaz.yamlexit 0 · 1.4s
    + spec.authentication.providers.magicLink: enabled
    ~ spec.authentication.mfa.mode: optional → required
    + spec.authentication.mfa.allowedMethods: [totp, webauthn]
    + spec.authentication.mfa.requireForAdmins: true
    ~ spec.authentication.session.timeoutMinutes: 720 → 480
    + spec.authentication.providers.oauth[google]: enabled
    ~ spec.branding.preset: indigo → professional
     
    7 change(s)
    Apply these changes? y
     
    ✓ Updated application acme
    ETag: 9c4e1a8b…
    7 change(s) applied.

    Why this matters in practice

    A few properties fall out of the design that we like:

    • Reviewable. Auth changes show up as PR diffs your security team can read. No more "who turned off MFA in staging."
    • Reproducible. authaz export round-trips your live tenant back to YAML. Bootstrap a new environment by importing it.
    • Concurrency-safe. Every apply is gated by an ETag from metadata.etag. If someone else changed the tenant since you exported it, the apply rejects until you re-export — or you pass --force and accept the consequences.
    • Validated locally. authaz validate runs the full schema + range checks (MFA grace 0–365 days, code length 4–10, max sessions 1–100, etc.) without ever calling the server. Good for CI.

    Where this is going

    We're working on the same shape for Authorization (RBAC roles, permissions, Zeratul relation tuples) and a Tenant kind that handles SAML connections, branding overrides, and quotas in the same file. Same authaz apply, same diff renderer, same ETag guard.

    If you want to try the CLI before the public release, join the waitlist — early adopters get the first builds.