FAQ & Troubleshooting
Indexed by what you see. Errors at the token endpoint follow standard OAuth
shapes (error plus error_description).
Check the service status page to see whether an Octet service is having problems.
At the login page
| Symptom | Cause and fix |
|---|---|
| QR page expires before the user finishes | The login session lives 90 seconds, or 180 seconds for a broker login. Restart the login, and have the phone ready |
| Phone shows "Check complete" but the login fails | The phone shows the same screen whether or not the login passed. Your app gets the result: the browser returns with error=access_denied. Ask the user to confirm they are in the required region and retry |
| Phone shows "Update required" | The app is too old to approve a sign-in. Update Octet Location from the App Store or Google Play, then scan again |
Browser returns error=access_denied |
Any failed verification or policy check, including a revoked device. LFA denies when any check fails, so this does not indicate 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 |
invalid_request: missing required parameter |
state or nonce is missing. Both are required, which is 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 direct-client 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, revoke the binding with
/v1/device/revoke and the next phone
binds automatically. Direct clients call it themselves. Broker clients ask Octet to call it. 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 location assertion is valid for 120 seconds.
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 is the same for both
platforms, and the acr you receive is identical. The app is on the App Store and
Google Play.
We use an identity broker such as Okta. Can we broker LFA?
Okta is supported today through signed authorization requests. Other brokers
that sign requests (RFC 9101) should work. Contact us first. 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. A client is a broker client when Octet has registered your
broker's issuer and request-signing key for it. You send that public key along
with your issuer URL. For Okta it is the key on the IdP page, not the org key. Device enrollment is forced off for brokers, so a broker user's
new phone is recovered when Octet revokes the old binding with
/v1/device/revoke, rather than with
octet_device_enroll. See the Okta guide.
Broker setups are configured with us rather than self-served. A signing key is exchanged and your issuer and request-signing key 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
Signed request object errors appear on LFA's own error page (HTTP 400), with no redirect, because LFA cannot trust the redirect target until the signed request is verified. Your app never receives a callback.
| Symptom | Cause and fix |
|---|---|
LFA shows this client must send a signed request object |
The client is a broker client, so a plain /authorize is rejected. Send the request as a signed object via request=<JWS>. On Okta, this means Enable signed requests is off, so Okta sends no request object. Turn it on |
LFA shows request object must carry login_hint |
The signed object is the only source of the binding identifier. Include login_hint inside the signed request object, not just the query string |
LFA shows signed request object failed verification |
The key Octet has on file does not match the one your broker signs with, or the object failed an iss, aud, exp, or nbf check. See the OIDC reference |
| 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. Ask Octet to revoke the old binding with /v1/device/revoke. The next login binds the new phone |
Signature verification is against pinned keys only. LFA does not fetch your
JWKS over the network. Octet pins the key you send. Send Octet the new public
key before you rotate, or valid logins will start failing. Only RS256 and ES256 are
accepted.