Scoped IAM backend
iam-scoped-api serves the noncritical and critical IAM permission APIs at
https://scoped.backend.iam.teamofsilicons.com. It is a separate process with
an explicit route list, sharing IAM's database, user identities, authorization,
keyrings, audit events, and durable worker. It does not create another identity
store or issue unrestricted IAM credentials.
Application and bundle integration
Register the application through the main IAM application-management API or frontend. The scoped host itself does not expose application creation or administration. The owning organization and application ID are chosen at registration; the hosted service does not reserve or automatically register one.
Set the application's base_url to
https://scoped.backend.iam.teamofsilicons.com, declare the IAM permissions that
Interface needs under app_scope.iam, and leave app_scope.external and
obo_endpoints empty. Registration still requires the application's actual,
signature-verifying webhook receiver and its secret. The stateless scoped IAM
service is not a webhook receiver and must not be entered as a placeholder
webhook destination.
An organization with bundle configuration available can include that application in its existing bundle.
The bundle issues the usual separate, single-use SLT for that application.
Interface's backend exchanges the SLT with the application's client secret at
main IAM /api/v1/app-auth/tokens. The resulting ordinary application access
token authorizes calls to the scoped backend. The app secret and refresh token
belong in the application's backend session storage.
The application needs critical-scope approval through the usual IAM review workflow. Application permission availability still applies; being included in a bundle does not override them. Every request is also limited by the user's current membership, role, capabilities, and selected organization grants. Removing a permission or revoking a session takes effect through IAM's normal revocation-aware token checks.
Authentication boundary
Every business route requires Authorization: Bearer <application access token>.
The token must have a nonempty client-application binding and the same audience
application. Direct IAM sessions, platform-administrator sessions, browser
cookies, and OBO tokens for another application are rejected. A valid ordinary
application session may represent either a Carbon or a Silicon; each handler
still enforces its own actor restrictions. An invalid bearer never falls back
to a browser cookie.
There is no OBO exchange, verification, proxy, or endpoint-discovery route.
GET /api/v1/application-scopes returns only the IAM permission catalog and
rejects query parameters, including app_id. It does not advertise another
application's OBO endpoints.
Public operational routes are /healthz, /readyz, /api/version,
/api/v1/version, and /api/v1/contracts. They disclose no user or organization
data. The backend retains normal version negotiation, CORS, size limits,
timeouts, admission control, structured errors, sensitive-header redaction,
request IDs, and no-store responses. Testing-environment credentials select the
same isolated testing data plane before authentication, but testing-environment
administration is available only through main IAM.
Available route groups
The paths and request/response schemas match the corresponding main IAM APIs in the OpenAPI contract.
| Route group | Available actions |
|---|---|
/api/v1/me |
Read the current subject's permitted identity/profile/contact fields |
/api/v1/application-scopes |
Discover IAM permissions only |
/api/v1/organization-ids/{org_id}/availability |
Check an organization ID for onboarding |
/api/v1/organizations and /{org_id} |
List, read, create, and update organizations according to scopes |
/{org_id}/members and /{membership_id} |
Read directory members, update assignments, remove members |
| Member authorization, tags, job roles, histories, promotions, demotions, and capabilities | Read or mutate only with the relevant published scope and the represented user's authority |
/{org_id}/directory/* |
Read self/member projections filtered by granted fields |
/{org_id}/carbon-invites/* and /join/* |
Manage invitations and complete verified invitation admission |
/{org_id}/silicons/* |
Read, create, update, remove, and request/complete credential rotation |
/{org_id}/tags/* and /trust/* |
Read and manage tag catalogs, member assignments, and trust configuration |
/{org_id}/role-change-requests and /approval-requests/* |
Submit, read, and decide eligible governance requests |
/{org_id}/sso, /sso/setup-link, /sso/test, /sso/authorize |
Read/manage entitled SSO and initiate validated SSO admission |
All abbreviated organization paths above begin with
/api/v1/organizations. Methods without a published IAM scope are absent: there
is no PATCH /api/v1/me, ownership transfer, Silicon webhook administration,
application administration, provider webhook, platform admin, or HTML surface.
Login, refresh, SLT exchange, first-party step-up challenges, and the WorkOS
callback stay on main IAM. A critical operation that requires step-up consumes
X-Step-Up-Token from IAM's existing verified-channel flow, bound to the same
underlying authentication session, action, and resource. IAM's provider callback
remains https://backend.iam.teamofsilicons.com/api/v1/sso/callback; the scoped
process therefore retains the canonical main IAM IAM_PUBLIC_BASE_URL.
For example, after exchanging the application's SLT:
curl --fail-with-body \
--header "Authorization: Bearer $SCOPED_ACCESS_TOKEN" \
https://scoped.backend.iam.teamofsilicons.com/api/v1/me
Organization mutations use the same Idempotency-Key, version preconditions,
and optional step-up headers documented in the main contract. Scopes grant the
application permission to request an action; they do not increase the user's
organization authority.
Rust SDK and mutation receipts
Use client.application_reads() for projected reads and
client.application_mutations() for organization, member, invitation, Silicon,
tag, trust, and governance mutations. The mutation methods return
models::ApplicationMutationObject (a JSON value), preserving absent fields and
any independently disclosed nested data. The existing strongly typed methods
remain available for direct IAM sessions. Deletes, verification-code delivery,
completed credential rotation, and SSO retain their existing typed SDK methods.
A successful write with no matching read permission can return only identifiers,
version/status metadata, or an empty object. Do not decode that response as a
full organization, membership, invitation, or trust model, and do not interpret
omitted fields as empty/default data. For example, a Carbon with only
organizations.create can receive { "id": "...", "org_id": "acme", "version": 1, "status": "active" }, without an organization name or timestamps. Silicon
creation still includes its generated identifiers and requested one-time
credential; store that credential immediately and never log the response.
use silicon_iam_client::{Client, Credential, Mutation, models};
async fn example(access_token: String) -> silicon_iam_client::Result<()> {
let client = Client::new("https://scoped.backend.iam.teamofsilicons.com")?
.with_credential(Credential::bearer(access_token));
let input = models::OrganizationCreate {
org_id: "acme".into(), name: "Acme".into(), logo: None, description: None,
};
let creating = Mutation::new();
let receipt = client.application_mutations()
.create_organization(&input, &creating).await?;
let organization_id = receipt.get("id").and_then(serde_json::Value::as_str);
let _ = organization_id;
Ok(())
}
OpenAPI documents both the direct IAM full response and the application mutation
object for these operations. Reuse the same Mutation on retries so an omitted
field does not cause an accidental second write with a new idempotency key.
Local operation
docker compose up scoped-api runs the separate process at
http://localhost:8081, using the normal migrations and API runtime role. Set
IAM_SCOPED_CORS_ALLOWED_ORIGINS to the local Interface origin when it differs
from http://localhost:3000. The scoped process defaults to four production DB
connections; its pool is separate from the main API pool.
For a native process, use the same IAM environment and override IAM_BIND_ADDR
to an unused address before cargo run --bin iam-scoped-api. Keep the canonical
main IAM backend and authentication URLs for provider callbacks and invitations.
Production installation
The current production ingress is nginx and Certbot on the IAM EC2 instance;
the older ALB migration templates in deploy/aws are not the live ingress.
Do not replay those templates to install this service.
- Build and verify one immutable image containing the updated main IAM binary,
migrations, and
iam-scoped-api. Apply migrations to production and the isolated testing database, then upgrade the main IAM API so scope registration and login use the same catalog. Preserve existing credentials and keyrings. - On the existing IAM instance, pull that image and extract
/opt/silicon-iam/scopedfrom it into the release directory. The image includes bothinstall.shandnginx.conf. - Run
bash install.sh --image '<registry/repository@sha256:digest>'. It copies the existing private API environment inside the host, limits the new pools, installs a dedicated systemd service on127.0.0.1:8081, and checks readiness plus absence of privileged routes. It does not change the main API service. - Add only
scoped.backend.iam.teamofsilicons.comin DNS, pointing to the current IAM public IP. Preserve the complete existing zone and verify authoritative resolution. Re-run the installer with the same image and--tlsto obtain the host-specific Let's Encrypt certificate and activate the separate nginx virtual host. The existing*.iam.teamofsilicons.comcertificate does not cover this deeper hostname. - Verify public TLS, readiness, version, an ordinary scoped application request, missing-scope denial, direct-IAM/OBO rejection, and that excluded paths return 404. Confirm the main IAM endpoint and worker remain healthy.
Production CORS includes https://interface.teamofsilicons.com and the canonical
IAM authentication origin, https://auth.iam.teamofsilicons.com. IAM's shared
production configuration requires the authentication origin even on the scoped
service. When replacing the list through --cors-origins, retain that origin and
add any other required exact HTTPS origins. Application bearer authentication
remains mandatory for every business route. The container port is loopback-only; public clients
reach it through TLS. API logs use the existing IAM CloudWatch log group with
the scoped-api tag, while the new nginx host disables access logging.
Rollback the scoped process by rerunning its installer with the previous compatible immutable image. For an initial-install rollback, disable the scoped systemd service and remove only its nginx virtual host and DNS record. Do not remove shared IAM database migrations, keyrings, main API service, or worker.