Protect an API
Require a valid access token issued for one API, write rules for who may call each route, and look up how route rules are matched.
Zero-Code checks every call to an API on the node, before the request reaches your code. A caller without a valid access token for this API is denied, and your service does not verify tokens, fetch keys or parse claims.
Use this guide for a service that programs call. For a service people open in a browser, see Protect a web app.
Before you begin
You need:
- A cluster with Zero-Code installed. See Install Zero-Code on a cluster.
- The callers of the API: each one is a machine-to-machine application or an AI agent.
Open the workload
In the AuthFI console, open Zero-Code > Kubernetes and select the cluster. On the Workloads tab, find the workload and choose Classify on its row.
Classify it as an App that serves an API
- The step asks what the workload is. Choose App.
- Under What does it serve?, turn on API.
- Choose Continue to Protect.
The console confirms that the workload is classified and opens the Protect step, which asks who may reach the workload.
Turn on the API door
Turn on API · software calls it. Every call must then carry a token issued for this service's audience, the name a token is issued for.
Write the route rules
A route rule says who may call a route. With the API switch on, the Protect step shows Route rules.
AuthFI drafts rules from the routes and callers it observed, so you start from what is really called and by whom. Choose Fill in the draft to load them, then correct them.
To add a rule:
- Choose the method and enter the path, for example
/ordersor/admin/*. - Choose Add route.
- On the new row, choose Signed in or Anyone.
- Choose + Requirement and pick what the caller must hold.
Requirements are chosen from your project's own roles, groups and permissions, not typed in. Each control is described in the route rule reference.
Choose where the service may connect
Under What it may reach, the console lists each destination it saw the service connect to. Tick the destinations the service needs.
To add a destination the service will need, enter its address or network and port, for example 10.0.0.0/8:5432, and choose Allow destination.
Save the draft and copy the audience
Choose Save draft. The console confirms with Draft saved: the rules are recorded, not enforced, until you turn protection on.
Saving gives the service its own API identity, registered as an application in your project. The Protect step now shows the audience. On the workload's page, under How it is reached, the API card has Copy audience.
Grant each caller access to the API
A caller must be granted access to the API before a token for it is issued. On the API card, choose Grant an application access to it. For a machine-to-machine application, the control on the application's page is Allow an API.
A caller then asks for a token by naming the audience in resource.
A token issued for another API is denied here.
Turn on protection
While the draft is saved and protection is off, every request is forwarded, and each one that would have been denied is recorded with its reason. Read the audit record and correct the rules until it reads right.
Then open the Protect step again and choose Turn on protection…, and confirm with Turn on protection. The button is available after 24 hours of watching.
The console confirms that protection is turned on. It applies on the nodes running the workload within 30 seconds. From then on, a call is denied unless its access token was issued for this API, including callers that work today. The API card shows token required.
Check that it works
Get a token for the API as a granted machine-to-machine application.
curl https://acme.authfi.io/oauth/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=client_credentials \
-d resource="$API_CLIENT_ID"$CLIENT_ID and $CLIENT_SECRET belong to the calling application. $API_CLIENT_ID is the audience you copied.
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6Ii4uLiJ9...",
"token_type": "Bearer",
"expires_in": 900
}Call a route that the caller's rule allows, with access_token as a Bearer token. The request reaches your service. Call the same route with no token, and the request is denied with missing_token before it reaches your service.
What is checked on each request
The node makes these checks in order, before your service sees anything.
Revocation is checked on every request. Revoke an AI agent or end a session, and the next request is denied, without waiting for the token to expire.
What a denied request receives
HTTP/1.1 403 Forbidden
WWW-Authenticate: Bearer realm="authfi", error="invalid_token"
X-Authfi-Ref: 7c1f0a2e
Content-Type: application/json
{ "error": "authfi_audience_mismatch", "message": "This credential was issued for a different service.", "ref": "7c1f0a2e" }ref identifies this denial in the audit record, with the caller, the route and the reason. Give it to whoever asks why they were denied.
To see which rules deny most, open Security > Signals. See What is recorded.
Read who is calling
As for a web app, the request reaches your service with the caller in headers: X-AuthFI-User-ID, X-AuthFI-Groups and X-AuthFI-Roles. A request from an AI agent also carries X-AuthFI-Agent-ID.
Route rule reference
A rule names a method and a path, and what a caller must hold to call it. You edit rules under Route rules in the Protect step.
Controls
The last four are under + Requirement. A caller needs every permission listed and any one of the groups or roles.
Example
Which rule decides a request
The first rule that matches a request decides it.
More specific rules are tried first: an exact path before a prefix, and a longer prefix before a shorter one. In the example, /v1/refunds is decided by its own rule, not by /*.
When no rule matches
The list of rules ends with a fixed row, everything else. Once the workload is protected, a request that matches no rule above it is denied. An API with rules is closed by default, and you open the routes you mean to open.
Paths that are always let through
These paths are answered without a token, so that health checks and sign-in keep working.
Hand a service back
To remove protection from a service, open Zero-Code > Kubernetes, select the cluster and open the Services tab. The tab lists what the node agent found listening in the cluster, and whether each service is protected.
Choose Unprotect on the service's row and confirm with Hand it back. Every policy for the service is deactivated, and its port reopens the next time the nodes fetch their rules.
Protect on the same row does the opposite, with no confirmation. The service is denied by default from the next time the nodes fetch their rules: every caller without a grant is dropped in the kernel.
Troubleshooting
Next steps
Service to service
Get a token for one API with the client credentials grant.
Accept agents at your own API
How an AI agent gets a token for your API, and what the token carries.
How enforcement works
Where each decision is made, and what monitor mode records.
The audit record
Find a denial by its reference.