Skip to content

WebAuthn and Passkeys

WebAuthn is the standard behind passkeys, security keys, and platform biometric unlock flows. SyncTV uses the configuration section name webauthn; product UI may call the feature passkeys.

Before enabling WebAuthn in production:

  • Use HTTPS.
  • Use a stable domain.
  • Configure rp_id and rp_origin correctly.
  • Use Redis in multi-replica deployments so challenge state is shared.

Default:

webauthn:
enabled: false

When enabled, passkey registration and login endpoints become available.

Relying Party ID. This is the site identity seen by authenticators.

Usually this is the main domain without scheme, port, or path:

webauthn:
rp_id: "example.com"

If the frontend is https://app.example.com, valid choices may include example.com or app.example.com depending on your product domain model.

Do not use:

  • https://example.com
  • example.com/login
  • localhost:8080

The exact frontend origin users access:

webauthn:
rp_origin: "https://app.example.com"

Origins include scheme, host, and optional port only. They do not include paths, query strings, or fragments.

Display name shown by the authenticator or operating system passkey UI.

Default:

webauthn:
rp_name: "SyncTV"

Additional allowed origins:

webauthn:
rp_origin: "https://app.example.com"
allowed_origins:
- "https://admin.example.com"

Keep this list minimal.

Default: false.

Allows subdomains of configured domains. Most deployments should keep this disabled.

Default: false.

Ignores origin port during validation. Use only for local development where frontend dev server ports change.

Do not enable it in production.

Default: 300.

How long passkey registration or login challenges remain valid.

Passkeys can be one local verification method. To enable user-level 2FA, a user must have at least two local verification methods, commonly:

  • password + email
  • password + webauthn
  • email + webauthn

OAuth2 does not participate in local 2FA.

WebAuthn challenges are single-use. In multi-replica deployments, challenge state must be shared across Pods.

Guidance:

  • Single-node: Redis optional.
  • Multi-replica or cluster.enabled=true: Redis required.