Docs/Integration Guides/Direct OIDC Integration

Direct OIDC Integration

LFA is a standard OIDC identity provider. Any stack that can federate to an external OIDC IdP, or perform an authorization-code flow, can consume LFA. You redirect to LFA, the user proves presence on their phone, and you get back an id_token whose claims carry the location verdict.

The Quick Start walks the wire protocol end to end. This page covers the integration decisions around it.


The one non-standard requirement

This is the direct path, where your app drives the OIDC flow itself. On this path your token exchange must include octet_user_id, your stable, opaque identifier for the user signing in. It drives device-to-user binding, and a production exchange without it is rejected (invalid_request).

Note

If you federate through an identity broker (Okta, Microsoft Entra ID, Auth0), the broker runs a fixed token exchange and cannot add octet_user_id. That path is still supported: the broker authenticates the front channel with a signed /authorize request instead, and the device binds to the verified login_hint. See Okta. The rest of this page assumes the direct path.

This shapes the library question. Any OIDC library can handle the /authorize redirect. For the token exchange, either:

  • your library lets you add a custom form field to the token request, so use it, or
  • perform the exchange yourself. It is one POST (see the Quick Start), and you can hand the resulting tokens back to your session layer.

Your callback handler knows which of your users is mid-login, because you initiated the redirect from their session or your primary IdP's. The identifier is already in hand when you exchange.

Selecting a policy per login

Pass octet_policy_id on /authorize to choose which registered policy this login must satisfy. One client can use many policies:

&octet_policy_id=country_uk

Omit it to use your client's pinned default. An unknown id is rejected rather than falling back, so a typo cannot silently weaken the check.

login_hint

If you pass login_hint on /authorize, LFA echoes it back in the id_token as the namespaced, unverified octet_login_hint claim. It is useful for correlating the response with the login you started. On the direct path it is pure passthrough: LFA does not verify or persist it, does not bind to it (octet_user_id on /token is the binding identifier), and never reflects it into identity claims such as email.

Strictness worth knowing up front

LFA is deliberately narrow. Misconfigurations fail immediately rather than degrading:

  • PKCE S256 is required. state and nonce are both mandatory.
  • Scopes are openid octet.location. Extra scopes a library adds (profile email) are ignored, and no profile claims come back.
  • No refresh tokens. A location proof is a statement about now. Re-prompt when you need fresh presence.
  • Authorization codes are single-use with a 60-second redemption window.

The full tables (endpoints, parameters, claims, errors) live in the OIDC Reference.

Gating on the result

Two levels. Use what fits:

  • Simple gate. Require acr == "urn:octet:loc:strong" in the id_token. That single check means hardware-attested presence with the policy passed.
  • Audit or downstream verification. Keep the octet_location_assertion claim, also mirrored as top-level location_assertion in the token response. It is a signed, 120-second statement of the region verdict, verifiable against the same JWKS.

Client registration

Clients are registered by the Octet team. Email hello@octetproof.com with your redirect URIs and the policies you need. See Prerequisites.

Where to go next

  • Device lifecycle. Binding, new phones, and revocation: the operational side of octet_user_id.
  • OIDC Reference. Every endpoint, parameter, claim, and error.