Authenticators
An authenticator is a tenant-configured instance of an authentication factor type. It can stand alone, or point at a connection for delivery-based factors such as email or SMS one-time codes.
This release ships the authenticator foundation plus a built-in TOTP authenticator and a delivery-based SMS OTP authenticator. TOTP enrollment data is encrypted per tenant, and verified TOTP enrollments can be used by authentication flows; SMS OTP needs no enrollment step, reading the destination phone number straight from the user's own attributes.
Authenticators vs. connections
A connection is a credentialed reference to an external provider — an SMS gateway, an email provider, an external identity provider. An authenticator is different: it's what actually challenges and verifies a user during sign-in (a one-time code, a passkey, or another factor-specific proof). Some authenticator types have nothing to connect to at all, while others optionally point at a connection purely for delivery. If a factor type needs to send something, it wraps a connection; if it doesn't, it stands alone.
Multiple authenticators of the same type
Nothing stops you from creating more than one authenticator of the same
type in a tenant (the only uniqueness rule is that display names must be
unique). This is genuinely useful for delivery-based types: if you have two
email connections — say, two providers, or one per region — you'd typically
configure one email_otp authenticator per connection, each with its own
display name and delivery settings.
For non-delivery types, there's usually little reason to configure more than one — most tenants will only ever need a single instance of each.
Built-in totp
Every tenant gets a ready-to-use TOTP authenticator, ID totp, with no
setup required — a flow can reference authenticatorId: "totp"
immediately. It uses fixed defaults (issuer "O2ID", 6 digits, 30-second
period, no progressive enrollment) and always appears first in
o2idctl authenticators list/GET /authenticators.
It's virtual: it isn't created via authenticators create, and
authenticators update/authenticators delete reject it. If you need
different settings — a different issuer name, digit count, or progressive
enrollment — create a separate totp-type instance with its own ID
instead of trying to modify the built-in one; both can coexist.
Managing authenticators requires a role with the
authenticators:read/authenticators:create/authenticators:update/
authenticators:delete scopes — see Managing Roles for how to create and assign roles.
Discovering available types
o2idctl authenticators list types
Each entry describes an authenticator type's type key, category, and
configSchema. The schema tells you which fields to pass via --field
when creating an authenticator, and which fields are secret.
Creating an authenticator
o2idctl authenticators create --type <a type from "authenticators list types"> --display-name <name> \
--field <configField>=value --field <secretField>=secret-value
--field is repeatable and carries both non-secret configuration and
secret values in one set. The service splits them before storing the
authenticator, encrypting only fields marked secret in the type's
configSchema. A --field value is parsed as JSON when possible (so
--field digits=6 or --field caseSensitive=true carry a number/bool
rather than a string), otherwise treated as a plain string.
The response never includes secret values:
{
"id": "a3f2d1c0b9e8d7c6a5f4e3d2c1b0a998",
"type": "...",
"category": "...",
"displayName": "Production factor",
"config": { "...": "..." },
"secretKeys": ["apiKey"],
"enabled": true,
"createdAt": "...",
"updatedAt": "..."
}
Delivery-based authenticators may pass --connection-id pointing at an
existing connection.
Listing and inspecting authenticators
o2idctl authenticators list
o2idctl authenticators get <id>
list (unlike list types) returns the tenant's own configured
authenticator instances — same shape as create's response, secret
values omitted.
Updating and deleting
o2idctl authenticators update <id> --display-name "Production factor"
o2idctl authenticators delete <id>
--field on update is merged key-by-key into the existing field set, so
you can rotate one secret without resubmitting every current secret
value. --display-name, --connection-id, and --enabled only change
when explicitly supplied.
API Reference
See the API Reference for the full request/response schemas.