Service-to-Service Authorization
Gate internal API calls between your backend services with the same policy engine that authorizes your users.
Vengtoo 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 Vengtoo via client credentials and calls
/access/v1/evaluationbefore accessing another service's resources
Step 1 — Create service subjects
Via Terraform
resource "vengtoo_subject" "billing_service" {
application_id = vengtoo_application.platform.id
name = "service:billing"
type = "service"
attributes = {
environment = "production"
team = "payments"
}
}
resource "vengtoo_subject" "webhook_service" {
application_id = vengtoo_application.platform.id
name = "service:webhook"
type = "service"
}
Via the Console
Go to Subjects → Create Subject. Set the Type to Service.
Step 2 — Write policies
Grant the billing service read access to invoices:
resource "vengtoo_policy" "billing_reads_invoices" {
application_id = vengtoo_application.platform.id
name = "billing_reads_invoices"
effect = "ALLOW"
subjects = [{ subject_id = vengtoo_subject.billing_service.id }]
resources = [{
resource_id = vengtoo_resource.invoices.id
actions = ["read", "list"]
}]
}
Grant the webhook service publish access to events:
resource "vengtoo_policy" "webhook_publishes_events" {
application_id = vengtoo_application.platform.id
name = "webhook_publishes_events"
effect = "ALLOW"
subjects = [{ subject_id = vengtoo_subject.webhook_service.id }]
resources = [{
resource_id = vengtoo_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 Vengtoo using OAuth2 client credentials and checks authorization before accessing another service's resources.
- curl
- Go
- Node.js
curl -X POST http://localhost:8181/access/v1/evaluation \
-H "Authorization: Bearer $VENGTOO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"subject": { "id": "service:billing", "type": "service" },
"resource": { "type": "invoice", "name": "inv-2024-001" },
"action": { "name": "read" }
}'
client := vengtoo.NewClient("",
vengtoo.WithOAuth(os.Getenv("VENGTOO_CLIENT_ID"), os.Getenv("VENGTOO_CLIENT_SECRET")),
vengtoo.WithBaseURL("http://localhost:8181"),
)
result, err := client.Authorize(ctx, &vengtoo.AuthorizeRequest{
Subject: vengtoo.Subject{ID: "service:billing", Type: "service"},
Resource: vengtoo.Resource{Type: "invoice", Name: invoiceID},
Action: vengtoo.Action{Name: "read"},
})
if !result.Decision {
return fmt.Errorf("service:billing not authorized to read invoice %s", invoiceID)
}
import { Vengtoo } from "@vengtoo/sdk";
const vengtoo = new Vengtoo({
clientId: process.env.VENGTOO_CLIENT_ID,
clientSecret: process.env.VENGTOO_CLIENT_SECRET,
baseUrl: "http://localhost:8181",
});
async function fetchInvoice(invoiceId: string) {
const { decision } = await vengtoo.authorize({
subject: { id: "service:billing", type: "service" },
resource: { type: "invoice", name: invoiceId },
action: { name: "read" },
});
if (!decision) throw new Error("service:billing is not authorized to read this invoice");
return await invoiceService.get(invoiceId);
}
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 "vengtoo_policy" "billing_prod_only" {
application_id = vengtoo_application.platform.id
name = "billing_prod_only"
effect = "ALLOW"
subjects = [{ subject_id = vengtoo_subject.billing_service.id }]
resources = [{
resource_id = vengtoo_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