Policies
A policy is the named rule a login must satisfy: which region the user must be in, how strong the device attestation must be, how fresh the proof may be, and how strict the anti-spoof verdict is.
Policies live on the LFA side, registered for your tenant by the Octet team alongside your OIDC clients. Your application never evaluates location data. It names a policy, and LFA answers pass or fail.
What a policy contains
| Field | Meaning | Today |
|---|---|---|
geofence |
The region the user must prove presence in | kind = "country" with an ISO 3166-1 alpha-2 code |
attestation_strength |
The minimum device-attestation floor: basic or strong |
Production policies run strong |
max_proof_age_s |
How old the phone's location proof may be, in seconds | 300 is the standard country-level window |
allow_plausible_spoofing_verdict |
Whether a PLAUSIBLE anti-spoof verdict passes, or only VERIFIED |
Default false (VERIFIED only) |
A registered policy looks like this. You do not write it. Octet registers it for you, and the shape is shown here to make it concrete:
[[tenant.policies]]
id = "country_uk"
version = 1
geofence = { kind = "country", iso_code = "GB" }
attestation_strength = "strong"
max_proof_age_s = 300
How a policy is selected
- Direct OIDC integrations pass
octet_policy_idon the/authorizerequest to pick a policy per login: one client, many policies. Omitting the parameter uses the client's pinned default. An unknown id is rejected. - Brokers (Okta and similar) pin the policy per registered client: one
client per policy. A broker runs a fixed token exchange and does not set
octet_policy_id, so each policy gets its own client. Enforcing UK presence for one app and US presence for another means two clients.
Geofences
Country-level geofences are what ships today. The user proves presence in a
country, identified by its ISO code, and the tokens assert exactly that. Finer
regions (state or province, city, custom areas) are on the roadmap, and the
policy schema (kind plus parameters) grows into them without changing your
integration.
See regions for how a region is expressed and matched on the device.
Attestation strength
This sets the minimum hardware backing LFA accepts.
strong. The proof must be rooted in the phone's secure hardware and carry a per-login signature from the enrolled device key. iOS and Android both reach it (see device attestation). This is the production floor, and a passing login carriesacr: urn:octet:loc:strong.basic. Accepts proofs below that floor. For test and development setups. Do not use it to gate anything that matters.
A proof that misses the floor is denied outright, not downgraded.
Proof freshness
max_proof_age_s bounds how stale the phone's proof may be when LFA checks it.
300 seconds matches the SDK's country-level proof window (see
time semantics). The location assertion LFA
then issues is itself valid for 120 seconds. Presence is asserted about now,
and nothing in the flow doubles as a long-lived credential.
Spoof-verdict floor
Every proof carries an anti-spoof verdict. The labels and the evidence behind
them are covered in verdicts. The policy sets where
the cutoff sits. LFA always rejects anything below PLAUSIBLE. Whether
PLAUSIBLE itself passes is yours to choose:
- Default (
allow_plausible_spoofing_verdict = false). OnlyVERIFIEDproofs pass. This is fail-closed, and recommended for anything security-relevant. - Opt-in (
true).PLAUSIBLEalso passes. Lower friction, lower assurance. For flows where a false rejection costs more than a marginal proof.
Where to go next
- Direct OIDC integration. The
octet_policy_idparameter in practice. - How a login works. Where the policy check sits in the flow.