Skip to content

Authorization Service API

An authorization service has two HTTPS JSON endpoints. The policy endpoint returns rules for an authorization token. The credential endpoint returns authentication headers for one allowed request.

ExfilGuard uses the same client certificate and limit on simultaneous calls for both endpoints. It does not follow redirects or use proxy settings from the environment. All bodies use application/json. Unknown fields in a response are rejected.

Policy

ExfilGuard sends:

{
  "authorization_token": "example-token",
  "audience": "deployment-prod",
  "source_ip": "192.0.2.10"
}

An active response has this shape:

{
  "active": true,
  "audience": "deployment-prod",
  "client_constraints": { "source_ip": "192.0.2.10" },
  "expires_at": 1893456000,
  "cache_until": 1893455940,
  "policy_version": "immutable-version-42",
  "rules": [
    {
      "action": "ALLOW",
      "methods": ["GET", "POST"],
      "url_pattern": "https://api.example.net/v1/**",
      "credential": {
        "credential_reference": "build-api",
        "protected_headers": ["authorization"],
        "body_access": "bounded_payload"
      }
    },
    {
      "action": "DENY",
      "url_pattern": "https://api.example.net/v1/admin/**"
    }
  ]
}

Times are Unix seconds. If methods is absent, the rule matches every method. "ANY" has the same meaning and must be the only entry. CONNECT is not allowed. Rules are checked in order, and the first match wins.

Only an allow rule may contain credential. ExfilGuard treats credential_reference only as a name. The reference, requested headers, body access, and request URL must fit a credential_limit on the selected client.

An inactive response needs only {"active": false}. This version supports only an exact source_ip constraint; authenticated connection identities are not yet supported. policy_version is an identifier containing 1 to 128 visible ASCII bytes.

Authentication headers

After both policies allow the request, ExfilGuard resolves and checks the destination and builds the exact outgoing request. It then sends this JSON to the same authorization service:

{
  "authorization_token": "example-token",
  "credential_reference": "build-api",
  "audience": "deployment-prod",
  "source_ip": "192.0.2.10",
  "request_nonce": "c0f515dd-6c97-4059-b2b8-4cc32abdf32f",
  "request_fingerprint": [148, 139, 21, 38, 21, 47, 137, 57, 194, 172, 55, 55, 203, 12, 63, 161, 6, 137, 2, 21, 28, 27, 171, 182, 35, 230, 249, 248, 166, 243, 28, 202],
  "finalized_request": {
    "version": 1,
    "scheme": "https",
    "origin_host": "api.example.net",
    "effective_port": 443,
    "authority": "api.example.net",
    "method": "POST",
    "raw_path_and_query": [47, 118, 49, 47, 105, 116, 101, 109, 115],
    "headers": [
      {"name": "host", "value": [97, 112, 105, 46, 101, 120, 97, 109, 112, 108, 101, 46, 110, 101, 116]},
      {"name": "content-length", "value": [51]},
      {"name": "authorization", "value": []}
    ],
    "protected_header_slots": ["authorization"],
    "body_kind": "buffered_payload",
    "body": [97, 98, 99],
    "payload_length": 3,
    "trailers": null
  }
}

Byte strings and the 32-byte fingerprint are JSON arrays of unsigned byte values. Header order and duplicate headers matter. Headers that the service must fill have empty values at this stage.

The service returns:

{
  "request_nonce": "c0f515dd-6c97-4059-b2b8-4cc32abdf32f",
  "request_fingerprint": [148, 139, 21, 38, 21, 47, 137, 57, 194, 172, 55, 55, 203, 12, 63, 161, 6, 137, 2, 21, 28, 27, 171, 182, 35, 230, 249, 248, 166, 243, 28, 202],
  "expires_at": 1893455910,
  "protected_headers": [
    {"name": "authorization", "value": [66, 101, 97, 114, 101, 114, 32, 46, 46, 46]}
  ]
}

The response must echo the full nonce and fingerprint, have an expiry in the future, and return exactly one value for every approved header and no others.

ExfilGuard rejects malformed, duplicate, missing, hop-by-hop, framing, forwarding, proxy, cookie, and unapproved headers. It checks the expiry when accepting the response. The request may finish after that time because it is already in progress. The response is never cached, retried, or reused. Before sending the request, ExfilGuard checks once more that its fingerprint has not changed.

The fingerprint is SHA-256 over the ASCII text exfilguard:finalized-request:v1, one NUL byte, and one definite-length CBOR map. The map uses these integer keys in order. Every length must use the shortest valid CBOR encoding.

Key Field CBOR type
0 version unsigned integer
1 scheme text string
2 normalized origin host text string
3 effective port unsigned integer
4 generated authority text string
5 method text string
6 raw path and query byte string
7 ordered headers array of two-element [text string, byte string] arrays
8 protected header slots array of text strings
9 body kind text string
10 payload byte string
11 payload length unsigned integer
12 trailers null

Headers that the service must fill are encoded with empty byte-string values. For the request above, the fingerprint is 948b1526152f8939c2ac3737cb0c3fa1068902151c1babb623e6f9f8a6f31cca.