Scopes Overview
Every route requires exactly one scope, granted per IntegrationClient when it’s created. There’s
no wildcard - an IntegrationClient sees only the routes for the scopes it’s been explicitly
granted.
What controls access to a request
Section titled “What controls access to a request”Three things combine, and all three are enforced on every request, not just checked once:
- Scope - does this key hold the scope this specific route requires? See the Scope Reference for the current list.
- Tenant - which tenant does this key belong to? You never pass this yourself; it comes from the key. A key can never see another tenant’s data, regardless of scope.
- Store restriction - is this key restricted to specific stores? If so, requests for any
other store return
404 not_found(see API Overview). If unrestricted, the key sees every store in its tenant.
Not OAuth2
Section titled “Not OAuth2”This is deliberately not OAuth2. There’s no token exchange, no scope consent screen, no refresh
token. A scope is a static grant on the IntegrationClient record, checked server-side on every
request - the same mental model as an API key with fine-grained permissions, which is what it is.
If you’re looking at the OpenAPI document and wondering why scopes aren’t
modeled as OAuth2 scopes there either: same reason - representing this as OAuth2 would misdescribe
how authentication actually works.
How a scope appears in the API Reference
Section titled “How a scope appears in the API Reference”Every operation in the API Reference lists its required scope via an
x-epos-scopes extension in the underlying OpenAPI document - visible on each operation’s page.
Requesting scopes
Section titled “Requesting scopes”Ask whoever manages your IntegrationClient (an EPOS owner) for exactly the scopes your
integration needs - see Security for why narrower is safer. See the
Scope Reference for what each one grants.