How It Works
This page follows a policy from the studio to your app, and one decision from the device to your backend.
The components
flowchart LR
W[You] -->|describe, review, sign| S[Magistrate studio]
S -->|publish| E[Octet policy engine]
E -->|1 signed policy bundle| A[Your app<br/>Octet Mobile SDK<br/>+ Magistrate module]
A -->|2 location proofs| E
E -->|3 decision + signed receipt| A
A -->|4 receipt| K[Your backend<br/>verifies and enforces]
J[Octet public keys<br/>/.well-known/] -.->|verify the receipt| K
- The studio turns what you describe into an OPL policy. When you sign it off, it publishes the policy to the engine.
- The engine compiles the policy and signs it as a policy bundle. It decides every request, and signs each decision as a receipt.
- The Magistrate module in your app checks that the bundle is signed by Octet, works out which location proofs the policy needs, asks the Octet Mobile SDK for them, and sends them to the engine.
- Your backend verifies the receipt with Octet's public key and enforces the decision.
Publishing a policy
- You describe the rule in the studio, or start from a template.
- The studio writes the policy in OPL and shows each rule as a plain sentence.
- You approve every sentence and sign off with your name.
- Sign and send publishes the policy. The engine checks it, compiles it and signs it with Octet's policy signing key.
- Your Octet contact connects the policy to your license.
- The engine always decides with the newest version. Apps fetch it the next time they check.
A device never runs a policy it can't verify. If the bundle's signature, format or version is wrong, the module refuses it and no decision is made.
One decision, in order
sequenceDiagram
participant A as Your app (Magistrate module)
participant E as Octet policy engine
participant K as Your backend
A->>E: GET /v1/bundle (signed policy)
A->>A: verify the bundle, read which proofs it needs
A->>E: POST /v1/decide/challenge
E-->>A: { decision_ref, nonce }
A->>A: Octet SDK makes the proofs, bound to the nonce
A->>E: POST /v1/decide { decision_ref, proofs }
E->>E: verify the proofs, decide the policy
E-->>A: { decision, reasons, obligations, receipt }
A->>K: the receipt, with the user's request
K->>K: verify the receipt, then enforce
- The module fetches the policy bundle and checks Octet's signature on it.
- It asks the engine for a one-time challenge. The challenge expires after a few minutes and works once.
- The Octet Mobile SDK makes the location proofs the policy needs, and binds each one to the challenge. A proof made for another request can't be reused.
- The engine verifies the proofs, decides the policy and signs the decision.
- Your app sends the receipt to your backend with the request it protects.
- Your backend verifies the receipt and decides what happens.
The module runs steps 1 to 4 in one call, decide.
Where the decision is made
The decision is made on Octet's servers, never on the device. The device only verifies the policy's signature and makes proofs. Anything the device computed could be changed by whoever holds it, so the answer that counts is the one the engine signs.
What the device discloses
The proofs say which country or state the device is in, and for a policy with a geofence, whether the device is inside that area. The decision and the receipt never carry coordinates.
What Octet keeps
Octet doesn't give you a way to fetch a receipt later, so store each receipt you act on, with the request it decided.