What is an identity domain?
An identity domain (idd) is an explicit namespace for a principal. Two users named user1 can belong to different domains. The string is supplied by trusted integration code or a configured token asserter; it is not proof of authentication. Speedle does not infer or validate a provider’s tenant model merely from the domain name.
Represent domains in policies and requests
grant user user1 from github read book
grant user user1 from IDCS.tenant01 read bookUse from <identity-domain> immediately after the principal name. In a PMS JSON policy, encode the same principal as idd=github:user:user1. In a decision request, represent this principal as:
{
"type": "user",
"name": "user1",
"idd": "github"
}A policy with from github matches that domain only. Omitting from matches that principal name across domains. Review this explicitly for multitenant applications; a domain string by itself does not validate a token. See identity/IAM and token assertion.
Before running the examples
Build ./bin/spctl, ./bin/speedle-pms and ./bin/speedle-ads using the quick start. Use Go 1.26.10 or Go 1.27.3 (or a newer patch on the same release branch), Bash, curl and Python 3. Run each terminal from the repository root. Use a fresh policy file for this page; reset it only after stopping both services.
Initialize an empty policy file:
printf '{}\n' > docs-policies.jsonIn terminal one, start PMS and leave it running:
./bin/speedle-pms --store-type file --filestore-loc ./docs-policies.json --endpoint 127.0.0.1:6733 --grpc-endpoint 127.0.0.1:0 --insecure=trueIn terminal two, start ADS and leave it running:
./bin/speedle-ads --store-type file --filestore-loc ./docs-policies.json --endpoint 127.0.0.1:6734 --grpc-endpoint 127.0.0.1:0 --insecure=trueRun the remaining commands in a third terminal. PMS and ADS share the file; watch propagates changes asynchronously. Confirm the intended update has reached ADS before relying on it. --insecure=true is only for this loopback example; see security for production connections. Explicit PMS addresses avoid changing ~/.spctlconfig. Stop both server terminals with Ctrl-C when finished.
Load the test policies
The fixture grants read to GitHub’s user1, write to Google’s user1, and rent to user1 from any domain. The lowercase domain values are demonstration namespaces.
./bin/spctl --pms-endpoint http://127.0.0.1:6733/policy-mgmt/v1/ create service --json-file website/tests/examples/idd.jsonCompare decisions
In order, expect Allow, Deny, Allow, Deny. A user in notgoogle cannot use Google’s write grant.
curl --fail --silent --show-error -H 'Content-Type: application/json' \
-d '{"subject":{"principals":[{"type":"user","name":"user1","idd":"github"}]},"serviceName":"booksvc","resource":"book","action":"read"}' \
http://127.0.0.1:6734/authz-check/v1/is-allowedcurl --fail --silent --show-error -H 'Content-Type: application/json' \
-d '{"subject":{"principals":[{"type":"user","name":"user1","idd":"gitlab"}]},"serviceName":"booksvc","resource":"book","action":"read"}' \
http://127.0.0.1:6734/authz-check/v1/is-allowedcurl --fail --silent --show-error -H 'Content-Type: application/json' \
-d '{"subject":{"principals":[{"type":"user","name":"user1","idd":"google"}]},"serviceName":"booksvc","resource":"book","action":"rent"}' \
http://127.0.0.1:6734/authz-check/v1/is-allowedcurl --fail --silent --show-error -H 'Content-Type: application/json' \
-d '{"subject":{"principals":[{"type":"user","name":"user1","idd":"notgoogle"}]},"serviceName":"booksvc","resource":"book","action":"write"}' \
http://127.0.0.1:6734/authz-check/v1/is-allowedJSON requests require Content-Type: application/json. Management examples use string policy IDs and permissions (plural); see the management API.