Skip to navigation

OAuth client credentials

Calling the APIs with short-lived OAuth 2.0 access tokens instead of an API key

If your security policy requires OAuth 2.0, your systems can call the APIs with an access token instead of an API key. Your system holds a client ID and secret, exchanges them for an access token that lasts one hour, and sends that token on each call. This is the client credentials grant of RFC 6749 §4.4.

Your own identity provider is not involved: emtelligent issues the credentials.

Creating a client

Anyone in your organization who can create API keys can create an OAuth client. Members see and manage the clients they created; owners and admins see and manage all of them. You choose:

  • A label, such as claims pipeline.
  • Scopes: the APIs the client may call. They are the same four scopes an API key has, with the same rule: one for each API your own code calls.
  • How the client authenticates to the token endpoint:
MethodHow the client proves itself
client_secret_basic (the default)The client ID and secret in an HTTP Basic Authorization header
client_secret_postThe client ID and secret as form fields in the request body
private_key_jwtA JWT assertion signed with your own private key. You provide an https URL where your public keys are published as a JWKS. There is no secret

The client authenticates only by the method it was created with. A client_secret_post client that sends a Basic header is refused.

The platform then shows the client ID (oac_…), the client secret (cs-emt-…) and the token URL. The secret is shown once and emtelligent stores only a hash of it, so store it in your secret manager straight away.

Getting an access token

Set the three values the platform showed you in your environment rather than putting them in code:

export EMT_TOKEN_URL='...'
export EMT_CLIENT_ID='oac_...'
export EMT_CLIENT_SECRET='cs-emt-...'

Then exchange them for a token:

curl -s -u "$EMT_CLIENT_ID:$EMT_CLIENT_SECRET" \
-d grant_type=client_credentials \
-d scope=ocr:process \
"$EMT_TOKEN_URL"
{ "access_token": "eyJhbGciOiJSUzI1NiIs…", "token_type": "bearer", "expires_in": 3599, "scope": "ocr:process" }

scope is optional. Without it, the token carries every scope the client was given. Asking for a scope the client was not given returns invalid_scope.

For client_secret_post, send the credentials as form fields instead: -d client_id=$EMT_CLIENT_ID -d client_secret=$EMT_CLIENT_SECRET.

Calling an API with the token

Send the access token wherever the API’s quickstart sends an API key. The token lasts one hour, and one token serves every call in that hour, so request a new one shortly before it expires rather than for every call.

This example keeps one token and replaces it a minute before it expires, then submits a document to the OCR API:

import os
import time
import requests
TOKEN_URL = os.environ["EMT_TOKEN_URL"]
CLIENT_ID = os.environ["EMT_CLIENT_ID"]
CLIENT_SECRET = os.environ["EMT_CLIENT_SECRET"]
class AccessToken:
"""One access token, replaced a minute before it expires."""
def __init__(self):
self._token = None
self._expires_at = 0.0
def get(self):
if self._token is None or time.time() > self._expires_at - 60:
response = requests.post(
TOKEN_URL,
auth=(CLIENT_ID, CLIENT_SECRET),
data={"grant_type": "client_credentials", "scope": "ocr:process"},
timeout=10,
)
response.raise_for_status()
body = response.json()
self._token = body["access_token"]
self._expires_at = time.time() + body["expires_in"]
return self._token
token = AccessToken()
with open("report.pdf", "rb") as fp:
response = requests.post(
"https://ocr.emtelligent.com/jobs",
data=fp,
headers={
"Authorization": f"Bearer {token.get()}",
"X-Filename": "report.pdf",
},
timeout=120,
)
response.raise_for_status()
job_id = response.json()["job_id"]

Libraries that implement the client credentials grant, such as requests-oauthlib and authlib, work as well. Point them at the token URL.

Rotating and revoking

  • Rotate the secret when your policy calls for it. The old secret stops working at the token endpoint immediately. Tokens it already obtained keep working until they expire, which is at most an hour later.
  • Revoke the client if the secret may have leaked. Its tokens are refused within a minute, and it can obtain no new ones.

When a member is removed, the OAuth clients they created can be revoked at the same time, as their API keys can. See Accounts and sign-in.

Usage and billing

Work done with a client’s tokens is billed to your organization in the same way as work done with an API key. Usage by credential shows it against the client ID. See Billing and usage.