Docs/Troubleshooting/FAQ & Troubleshooting

FAQ & Troubleshooting

Indexed by what you see. Errors at the token endpoint follow standard OAuth shapes (error plus error_description).


At the login page

Symptom Cause and fix
QR page expires before the user finishes The login session lives 90 seconds. Restart the login, and have the phone ready
Phone shows "Verification failed" The proof did not satisfy the policy: the user is outside the region, the proof is stale, or the spoof verdict is below the floor. The browser receives access_denied
Browser returns error=access_denied Any failed verification or policy check, including a revoked device. This is fail-closed behaviour, not an outage

At /authorize

Symptom Cause and fix
invalid_request: PKCE S256 code_challenge is required Your library is not sending PKCE, or sends plain. Enable S256
missing field state or missing field nonce Both are mandatory, stricter than the OIDC spec. Configure your library to send both
Unknown octet_policy_id rejected Deliberate, because a typo must not fall back to a different policy. Check the id against your registered policies

At /token

Symptom Cause and fix
invalid_request: octet_user_id is required Every production exchange must name the signing-in user. See the Quick Start
invalid_grant: this device is bound to a different user The phone that proved presence is enrolled to another account. The user must use their own phone
invalid_grant: a new device requires enrollment The user already has a bound device and just used a different one. Re-verify the user, then retry with octet_device_enroll=true. See Device lifecycle
invalid_grant: code expired / already redeemed Codes are single-use with a 60-second window. Exchange immediately in the callback, and check for duplicate callback invocations

Common questions

Does the user have to enroll before the first login? No. The first successful login enrolls the phone and binds it to the octet_user_id you send. It is one flow, slightly longer the first time.

How does a user switch phones? Two paths. If the user still controls their account, use your own step-up verification plus octet_device_enroll=true. If the phone is lost or stolen, call /v1/device/revoke and the next phone binds automatically. See Device lifecycle.

Can I get the user's coordinates? No. They never leave the phone. LFA can only tell you the region verdict. See Trust & Privacy.

Why are there no refresh tokens? A location proof is a statement about the present moment. If you need fresh presence, run a fresh login. The assertion's 120-second validity is the design, not a limitation.

Why did my OIDC library's profile email scopes return nothing? LFA advertises openid octet.location only and asserts no identity claims for direct clients. The extras are ignored rather than rejected.

Is Android supported? Yes. The Octet Location app runs on iOS and Android, and both reach the same urn:octet:loc:strong assurance: iOS via Apple App Attest, Android via hardware key attestation chained to a Google root. Your integration does not change. The platform difference is invisible on the wire, and the acr you receive is identical. iOS is on the App Store, and Android is in closed testing.

We use Okta, Entra, or Auth0. Can we broker LFA? Yes. A broker cannot add octet_user_id on the fixed token exchange, so LFA authenticates the front channel instead: the broker signs its /authorize request as a signed request object (RFC 9101, "JAR"), and LFA binds the device on the login_hint inside that verified object. Octet marks your client as a broker server-side and pins your org's request-signing key, which you supply along with your issuer URL. Device enrollment is forced off for brokers, so a broker user's new phone is recovered by an admin /v1/device/revoke rather than octet_device_enroll. See the Okta guide.

Note

Broker setups are configured with us rather than self-served. A signing key is exchanged and your org's request objects are pinned on the LFA side. Contact hello@octetproof.com and we will validate the flow against your org before you enable it for users.

Brokered clients (Okta, Entra, Auth0)

Symptom Cause and fix
invalid_request: signed request object required The client is configured as a broker, so a plain /authorize is rejected fail-closed. Send the request as a signed object via request=<JWS>
invalid_request with no login_hint in the request object The signed object is the only source of the bind user. Include login_hint inside the signed request object, not just the query string
Broker /authorize rejected even though you are sending request= Okta's Enable signed requests toggle is off, so the object is not signed with your org key. Turn it on. It is required
Login fails at username matching Leave IdP Username at its default. A Factor-only IdP always matches on preferred_username, which LFA emits for broker clients, and it ignores any custom expression you set. If it still fails, read debugContext.debugData.errorMessage in the System Log. The visible error text names something other than the actual cause
invalid_grant with a new device rejected for a broker user Brokers cannot enroll a replacement device. Have an admin call /v1/device/revoke, and the next login binds the new phone
Note

Signature verification is against pinned keys only. LFA does not fetch your JWKS over the network. Pin your org's current signing key and refresh it manually when you rotate, or valid logins will start failing. Only RS256 and ES256 are accepted.