auth

Authentication backend selection. Detailed per-backend configuration lives under Access Control; this page is the horizon.yaml shape.

Shape

auth:
  backend: local            # or: ldap

  local:
    users:
      - username: admin
        passwordHash: "$argon2id$v=19$..."
        roles: [admin]

  ldap:
    url: ldaps://ldap.corp:636
    bindDn: "cn=horizon,ou=services,dc=corp"
    bindPassword: "${HORIZON_LDAP_BIND_PW}"
    userBaseDn: "ou=people,dc=corp"
    userFilter: "(uid={username})"
    displayNameAttr: cn
    groupStrategy: memberOf
    groupBaseDn: ""
    memberAttr: member
    timeoutMs: 5000
    tlsInsecure: false
    groupMappings:
      - { group: "cn=horizon-admin,ou=groups,dc=corp", role: admin }
      - { group: "*", role: viewer }

  breakGlass:
    username: emergency-admin
    passwordHash: "${HORIZON_BREAK_GLASS_HASH}"
    roles: [admin]

auth.backend

Field Type Default Required Notes
backend enum: local | ldap local no Active backend. Switching to ldap causes the local block to be ignored at login time (a warning is logged at startup if both are populated).

The two blocks are mutually exclusive at runtime. Leaving the inactive block populated is allowed (useful for staging — flip the backend without re-typing the other side) but logs a warning.

auth.local

Field Type Default Required Notes
local.users array [] required when backend: local (must be non-empty) Array of user objects.
local.users[].username string (min 1) yes Unique login name.
local.users[].passwordHash string (min 1) yes Argon2id hash. Generate via pnpm --filter bff cli:hash. Never store plain passwords.
local.users[].roles string[] [] no Roles assigned to this user. Empty array means no permissions (sessions still created; UI shows “no access” for everything).

See Local Backend for hash generation and operational notes.

auth.ldap

Required when backend: ldap. groupMappings must be non-empty.

Field Type Default Required Notes
ldap.url string (min 1) yes Directory URL. ldaps:// (TLS) or ldap:// (plaintext).
ldap.bindDn string "" no Service-account DN for searches. Empty = anonymous bind (only works if the directory permits).
ldap.bindPassword string "" no Service-account password. Use ${VAR} interpolation.
ldap.userBaseDn string (min 1) yes Base DN for user searches.
ldap.userFilter string (uid={username}) no Search filter template. {username} is substituted (RFC 4515 escaped). For Active Directory use (sAMAccountName={username}).
ldap.displayNameAttr string cn no LDAP attribute containing the user’s display name.
ldap.groupStrategy enum: memberOf | search memberOf no memberOf reads the attribute off the user entry (AD-style). search searches groupBaseDn for groups containing the user DN (OpenLDAP-style).
ldap.groupBaseDn string "" required if groupStrategy: search Base DN for group searches.
ldap.memberAttr string member no Group attribute listing members. Only used when groupStrategy: search.
ldap.timeoutMs number 5000 no LDAP bind / search timeout in milliseconds. Positive integer.
ldap.tlsInsecure boolean false no Skip TLS certificate validation. Never use in production.
ldap.groupMappings array [] required when backend: ldap (must be non-empty) Group DN → Horizon role bindings.
ldap.groupMappings[].group string (min 1) yes LDAP group DN, or the literal "*" (matches any authenticated user — fallback).
ldap.groupMappings[].role string (min 1) yes Horizon role assigned when the user’s groups include group. First match wins; multiple matches union.

See LDAP Backend for the full login flow and operational notes.

auth.breakGlass

Emergency admin credential, honored only when backend: ldap AND the LDAP probe is currently failing.

Field Type Default Required Notes
breakGlass.username string (min 1) yes (if block present) Break-glass login name.
breakGlass.passwordHash string (min 1) yes (if block present) Argon2id hash.
breakGlass.roles string[] ['admin'] no Roles granted during the break-glass session. Defaults to admin since the purpose is recovery.

See Break-Glass Access for the trigger conditions and audit behavior.

Bootstrap validation summary

Condition Result
backend: local and local.users empty startup fails
backend: ldap and ldap missing startup fails
backend: ldap and ldap.groupMappings empty startup fails
backend: ldap and local.users populated warning at startup
breakGlass populated but backend: local warning at startup (block is unused in local mode)