[{"data":1,"prerenderedAt":21},["ShallowReactive",2],{"doc-authentication":3},{"blocks":4,"markdown":20},[5,8,12,14,18],{"kind":6,"html":7},"html","\u003Cp>Every call carries an API key as a bearer token:\u003C\u002Fp>\n",{"kind":9,"lang":10,"code":11},"code","bash","curl https:\u002F\u002Fapi.formalogic.io\u002Fv1\u002Foracles \\\n  -H \"Authorization: Bearer fk_live_…\"",{"kind":6,"html":13},"\u003Cp>There is no other scheme. No query parameter, no cookie, no signed URL — a\ncredential in a URL ends up in a proxy log, a browser history and a bug report,\nand offering it as an option means it will eventually be used.\u003C\u002Fp>\n\u003Ch2 id=\"getting-a-key\">Getting a key\u003C\u002Fh2>\n\u003Cp>Keys are created on the \u003Ca href=\"https:\u002F\u002Fapp.formalogic.io\u002Fkeys\" target=\"_blank\" rel=\"noopener noreferrer\">API keys\u003C\u002Fa> page. The token is shown \u003Cstrong>once\u003C\u002Fstrong>, at\nthe moment it is created, and is not recoverable afterwards — we store a hash of\nit, so there is nowhere to read it back from.\u003C\u002Fp>\n",{"kind":15,"path":16,"label":17},"console","\u002Fkeys","Create or revoke a key",{"kind":6,"html":19},"\u003Cp>Give each caller its own key. Quota is per organisation, so a second key does not\nbuy a second allowance; what it buys is the ability to revoke one integration\nwithout breaking the others, and a usage log that tells you which one is\nspending.\u003C\u002Fp>\n\u003Ch2 id=\"two-identities-and-they-never-mix\">Two identities, and they never mix\u003C\u002Fh2>\n\u003Cp>An \u003Cstrong>API key\u003C\u002Fstrong> authenticates a machine against the oracle API. It knows nothing\nabout people and has no role. The only thing it can read about your account is\n\u003Ca href=\"\u002Fme\">which organisation it belongs to\u003C\u002Fa> — no members, no usage, no billing,\nand nothing it could change.\u003C\u002Fp>\n\u003Cp>A \u003Cstrong>console session\u003C\u002Fstrong> authenticates a person against the console — minting keys,\nchanging a plan, reading usage. It cannot call an oracle.\u003C\u002Fp>\n\u003Cp>The two run in separate processes with separate credentials against separate\ndatabase roles. A key that leaks cannot be used to raise your plan or list your\nteam; a console session that leaks cannot be used to spend your credits.\u003C\u002Fp>\n\u003Ch2 id=\"what-each-refusal-means\">What each refusal means\u003C\u002Fh2>\n\u003Cp>All four are \u003Ccode>401\u003C\u002Fcode>, and the code says which — because the remedies differ and a\nclient that cannot tell them apart will retry something that is never going to\nstart working.\u003C\u002Fp>\n\u003Cdiv class=\"doc-table\">\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Code\u003C\u002Fth>\n\u003Cth>What happened\u003C\u002Fth>\n\u003Cth>What to do\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KEY_MISSING\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>No \u003Ccode>Authorization\u003C\u002Fcode> header, or not a bearer token\u003C\u002Ftd>\n\u003Ctd>Send the header\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KEY_UNKNOWN\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>The token is not one of ours\u003C\u002Ftd>\n\u003Ctd>Check for a truncated paste\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KEY_REVOKED\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>It was valid and someone revoked it\u003C\u002Ftd>\n\u003Ctd>Mint a new one; do not retry\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>KEY_EXPIRED\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>It carried an expiry and passed it\u003C\u002Ftd>\n\u003Ctd>Mint a new one; do not retry\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n\u003C\u002Fdiv>\n\u003Cp>\u003Ccode>KEY_REVOKED\u003C\u002Fcode> and \u003Ccode>KEY_EXPIRED\u003C\u002Fcode> are permanent. Backing off and retrying will\nproduce the same answer forever.\u003C\u002Fp>\n\u003Cp>One refusal is not about the key at all: \u003Ccode>403 ORG_DISABLED\u003C\u002Fcode> means the key is\nfine and the organisation it belongs to is not active. Keep the key — minting\nanother would be refused the same way — and write to support@formalogic.io.\nThe console answers the same code to every member of that organisation.\u003C\u002Fp>\n\u003Cp>Note what is \u003Cstrong>not\u003C\u002Fstrong> in that list: a spent allowance answers \u003Ccode>402 QUOTA_EXCEEDED\u003C\u002Fcode>, not \u003Ccode>401\u003C\u002Fcode>. Your credential is fine. See\n\u003Ca href=\"\u002Flimits\">Limits and credits\u003C\u002Fa>.\u003C\u002Fp>\n\u003Ch2 id=\"rotating-a-key\">Rotating a key\u003C\u002Fh2>\n\u003Cp>Mint the replacement first, move traffic to it, then revoke the old one. Revoking\ntakes effect on the next request — there is no cache to wait out and no grace\nperiod, which is what makes it useful when a key has leaked.\u003C\u002Fp>\n","# Authentication\n\n> One header, one kind of credential, and four refusals that mean different things.\n\nEvery call carries an API key as a bearer token:\n\n```bash\ncurl https:\u002F\u002Fapi.formalogic.io\u002Fv1\u002Foracles \\\n  -H \"Authorization: Bearer fk_live_…\"\n```\n\nThere is no other scheme. No query parameter, no cookie, no signed URL — a\ncredential in a URL ends up in a proxy log, a browser history and a bug report,\nand offering it as an option means it will eventually be used.\n\n## Getting a key\n\nKeys are created on the [API keys](https:\u002F\u002Fapp.formalogic.io\u002Fkeys) page. The token is shown **once**, at\nthe moment it is created, and is not recoverable afterwards — we store a hash of\nit, so there is nowhere to read it back from.\n\n[Create or revoke a key](https:\u002F\u002Fapp.formalogic.io\u002Fkeys)\n\nGive each caller its own key. Quota is per organisation, so a second key does not\nbuy a second allowance; what it buys is the ability to revoke one integration\nwithout breaking the others, and a usage log that tells you which one is\nspending.\n\n## Two identities, and they never mix\n\nAn **API key** authenticates a machine against the oracle API. It knows nothing\nabout people and has no role. The only thing it can read about your account is\n[which organisation it belongs to](https:\u002F\u002Fdocs.formalogic.io\u002Fme) — no members, no usage, no billing,\nand nothing it could change.\n\nA **console session** authenticates a person against the console — minting keys,\nchanging a plan, reading usage. It cannot call an oracle.\n\nThe two run in separate processes with separate credentials against separate\ndatabase roles. A key that leaks cannot be used to raise your plan or list your\nteam; a console session that leaks cannot be used to spend your credits.\n\n## What each refusal means\n\nAll four are `401`, and the code says which — because the remedies differ and a\nclient that cannot tell them apart will retry something that is never going to\nstart working.\n\n| Code | What happened | What to do |\n|---|---|---|\n| `KEY_MISSING` | No `Authorization` header, or not a bearer token | Send the header |\n| `KEY_UNKNOWN` | The token is not one of ours | Check for a truncated paste |\n| `KEY_REVOKED` | It was valid and someone revoked it | Mint a new one; do not retry |\n| `KEY_EXPIRED` | It carried an expiry and passed it | Mint a new one; do not retry |\n\n`KEY_REVOKED` and `KEY_EXPIRED` are permanent. Backing off and retrying will\nproduce the same answer forever.\n\nOne refusal is not about the key at all: `403 ORG_DISABLED` means the key is\nfine and the organisation it belongs to is not active. Keep the key — minting\nanother would be refused the same way — and write to support@formalogic.io.\nThe console answers the same code to every member of that organisation.\n\nNote what is **not** in that list: a spent allowance answers `402\nQUOTA_EXCEEDED`, not `401`. Your credential is fine. See\n[Limits and credits](https:\u002F\u002Fdocs.formalogic.io\u002Flimits).\n\n## Rotating a key\n\nMint the replacement first, move traffic to it, then revoke the old one. Revoking\ntakes effect on the next request — there is no cache to wait out and no grace\nperiod, which is what makes it useful when a key has leaked.\n",1793819973842]