import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Proof Binding

:::note[In short]

By default the SDK may reuse a recent buffered proof for a predicate call. Three optional parameters change that: `sessionNonce` binds a proof to one login, `decisionRef` binds it to one authorization decision, and `forceFresh` just mints a new proof with no binding.

:::

## The freshness buffer

A predicate call can be answered from a buffered proof that is still inside its validity window, rather than generating a new one every time. That keeps repeated checks cheap. When you need a proof tied to a specific request, or a proof made at this exact moment, use one of the three controls below. Each is an optional parameter on `isWithin`, `isOutside`, and `contains`.

## Session binding -- `sessionNonce`

Bind a proof to a single login. Your login backend issues a one-time nonce; you pass it as `sessionNonce` (opaque bytes, 1 to 512). The SDK commits a hash of the nonce inside the signed proof as a `sessionBinding` stage, so a verifier can confirm the proof was made for that login. Only the hash rides the proof, never the raw nonce. Passing a nonce forces a fresh proof (it bypasses the buffer). An empty or over-512-byte nonce returns `INDETERMINATE / INVALID_SESSION_NONCE` with no proof.

<Tabs groupId="platform">
  <TabItem value="swift" label="Swift (iOS)">

```swift
let nonce = try await loginBackend.issueNonce()
let v = await sdk.loc.isWithin(region: .country(isoCode: "US"), sessionNonce: nonce)
if v.result == .yes { send(v.proof!, to: loginBackend) }
```

  </TabItem>
  <TabItem value="kotlin" label="Kotlin (Android)">

```kotlin
val nonce: ByteArray = loginBackend.issueNonce()
val v = sdk.loc.isWithin(OctetRegion.country("US"), sessionNonce = nonce)
if (v.result == OctetVerdict.Result.YES) send(v.proof!!, loginBackend)
```

  </TabItem>
</Tabs>

## Decision binding -- `decisionRef`

Bind a proof to a specific authorization decision. Pass an opaque, host-minted decision identifier (1 to 256 characters) as `decisionRef`. The SDK fetches a decision-scoped upload nonce (`POST /v1/proofs/challenge` with a `decision_ref` body) so the proofs backend stamps a trusted `challenge_decision_ref` anchor, and it tags the upload envelope with two opaque top-level fields: `decision_ref` (the find key you gave) and `region_ref` (the proof's own claimed region in canonical form, for example `country(US)`). A relying party can then fetch and trust exactly the proof for one decision. An over-256-character ref returns `INDETERMINATE / INVALID_DECISION_REF` with no proof and no network call.

The difference from `sessionNonce`: a session nonce binds the proof to a login and commits a hash inside the signed proof; a decision ref binds the uploaded proof to a decision through the upload envelope, and is the key a backend fetches it by.

## Force fresh -- `forceFresh`

Set `forceFresh: true` to bypass the buffer and mint a proof for this call, with none of the binding semantics above: no committed nonce, no decision-scoped challenge, no envelope tags. Use it when a proof must reflect the device's location right now rather than a cached fix that is still valid, for example a "refresh" button. It does not loosen any spoof check: a fresh proof still runs the full pipeline, and a call that cannot generate one returns `noFix`, never a cached `YES`.

Combining `forceFresh` with a binding is redundant but harmless, because a binding already bypasses the buffer.

## Choosing between them

| Goal | Use |
|---|---|
| Prove for one login, verifiable in the signed proof | `sessionNonce` |
| Bind an uploaded proof to one authorization decision a backend fetches | `decisionRef` |
| A proof of the device's location right now, no binding | `forceFresh` |
| Cheap repeated checks | none (let the buffer serve) |

## Where to go next

- [Predicates](/docs/api-reference/predicates/): the exact parameter signatures.
- [Verifying Proofs](/docs/concepts/verifying-proofs/): how a bound proof is checked.
- [Serialization](/docs/api-reference/serialization/): the fields a proof commits and serializes.
