Service-to-Service Authorization
Gate internal API calls between your backend services with the same policy engine that authorizes your users.
AuthzX treats every caller as a subject — users, services, AI agents. A service is just a subject with type: "service". No special infrastructure required.
How it works
- Create a subject for each service (e.g.,
service:billing,service:webhook) - Write policies that grant those subjects access to specific resources and actions
- Each service authenticates to AuthzX via client credentials and calls
/v1/authorizebefore accessing another service's resources
Step 1 — Create service subjects
Via Terraform
resource "authzx_subject" "billing_service" {
application_id = authzx_application.platform.id
name = "service:billing"
type = "service"
attributes = {
environment = "production"
team = "payments"
}
}
resource "authzx_subject" "webhook_service" {
application_id = authzx_application.platform.id
name = "service:webhook"
type = "service"
}
Via the Console
Go to your application → Subjects → Create Subject. Set the type to service.
Step 2 — Write policies
Grant the billing service read access to invoices:
resource "authzx_policy" "billing_reads_invoices" {
application_id = authzx_application.platform.id
name = "billing_reads_invoices"
effect = "ALLOW"
subjects = [{ subject_id = authzx_subject.billing_service.id }]
resources = [{
resource_id = authzx_resource.invoices.id
actions = ["read", "list"]
}]
}
Grant the webhook service publish access to events:
resource "authzx_policy" "webhook_publishes_events" {
application_id = authzx_application.platform.id
name = "webhook_publishes_events"
effect = "ALLOW"
subjects = [{ subject_id = authzx_subject.webhook_service.id }]
resources = [{
resource_id = authzx_resource.events.id
actions = ["publish"]
}]
}
You can also use roles — create a service_reader role and assign it to multiple service subjects.
Step 3 — Check before every internal call
Each service authenticates to AuthzX using OAuth2 client credentials and checks authorization before accessing another service's resources.
Node.js (using @authzx/sdk)
import { AuthzXClient } from "@authzx/sdk";
const authzx = new AuthzXClient({
clientId: process.env.AUTHZX_CLIENT_ID,
clientSecret: process.env.AUTHZX_CLIENT_SECRET,
agentUrl: "http://localhost:8181",
});
async function fetchInvoice(invoiceId: string) {
const { allowed } = await authzx.authorize({
subject: { id: "service:billing", type: "service" },
resource: { type: "invoice", name: invoiceId },
action: { name: "read" },
});
if (!allowed) throw new Error("service:billing is not authorized to read this invoice");
return await invoiceService.get(invoiceId);
}
Go (using authzx-go)
client := authzx.NewClient(
authzx.WithClientCredentials(os.Getenv("AUTHZX_CLIENT_ID"), os.Getenv("AUTHZX_CLIENT_SECRET")),
authzx.WithAgentURL("http://localhost:8181"),
)
result, err := client.Authorize(ctx, &authzx.AuthorizeRequest{
Subject: authzx.Subject{ID: "service:billing", Type: "service"},
Resource: authzx.Resource{Type: "invoice", Name: invoiceID},
Action: authzx.Action{Name: "read"},
})
if !result.Allowed {
return fmt.Errorf("service:billing not authorized to read invoice %s", invoiceID)
}
curl
curl -X POST http://localhost:8181/v1/authorize \
-H "Authorization: Bearer $AUTHZX_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": { "id": "service:billing", "type": "service" },
"resource": { "type": "invoice", "name": "inv-2024-001" },
"action": { "name": "read" }
}'
Using ABAC conditions
You can add attribute-based conditions to service policies. For example, only allow the billing service to read invoices in production:
resource "authzx_policy" "billing_prod_only" {
application_id = authzx_application.platform.id
name = "billing_prod_only"
effect = "ALLOW"
subjects = [{ subject_id = authzx_subject.billing_service.id }]
resources = [{
resource_id = authzx_resource.invoices.id
actions = ["read"]
}]
conditions = [{
field = "subject.attributes.environment"
operator = "equals"
value = "production"
}]
}
Audit trail
Every service-to-service authorization decision is logged in the Decision Log with the full context — subject, resource, action, matched policy, and latency. Filter by type: service to see only service calls.
Related
- Subjects — Creating and managing service subjects
- OAuth2 Client Credentials — Authenticating services
- ABAC Conditions — Attribute-based policies for services
- Terraform Provider — Managing service subjects and policies as code