API Reference Overview¶
Introduction¶
The Identity Atlas UI is backed by a Node.js + Express REST API that queries the PostgreSQL database. All endpoints are prefixed with /api/ and require Entra ID JWT authentication unless explicitly noted below.
The backend runs on port 3001 and connects to PostgreSQL using a connection pool. In development, it can run against mock data (set USE_MOCK=true).
Base URL¶
Resolve every /api/... path in this reference against the deployment's public base URL. For any deployment reached through a reverse proxy, tunnel, or TLS terminator, set PUBLIC_BASE_URL (e.g. https://atlas.example.com) and resolve /api against it — so the external base is https://atlas.example.com/api. This is the authoritative external base and removes any dependency on (spoofable) Host/X-Forwarded-* headers. A direct, un-proxied deployment is reached at http://localhost:3001/api. Crawlers running inside the worker container reach the API at the container-internal http://web:3001/api.
flowchart LR
Browser["Browser\n(React + MSAL)"] -->|"Bearer JWT"| API["Express API\nPort 3001"]
API -->|JWT validation| Auth["Auth Middleware\n(Entra ID)"]
Auth --> Routes["Route Handlers"]
Routes --> SQL["PostgreSQL\nTables + Views + Mat. Views"]
Authentication¶
Every request must include a valid Entra ID JWT in the Authorization header:
Two endpoints are exempt and do not require a token:
| Endpoint | Description |
|---|---|
GET /api/health |
Health check. Returns { status: "ok", mode: "sql" \| "mock" } |
GET /api/auth-config |
MSAL configuration for the frontend. Returns { enabled, clientId?, tenantId? } |
Security Features¶
| Feature | Detail |
|---|---|
| Tenant ID validation | Every token is validated against the configured TENANT_ID env var |
| Role-based access control | Optional — set AUTH_REQUIRED_ROLES env var to a comma-separated list of required Entra ID app roles |
| Rate limiting | 30 requests/min per IP on pre-auth endpoints |
| Security headers | helmet middleware applies CSP, HSTS, X-Frame-Options, and Referrer-Policy on all responses |
| Request body size | Capped at 100 KB (express.json({ limit: '100kb' })) |
Environment Variables¶
| Variable | Required | Description |
|---|---|---|
TENANT_ID |
Yes (auth mode) | Entra ID tenant ID — used to validate JWT tid claim |
CLIENT_ID |
Yes (auth mode) | App registration client ID — returned to frontend via /api/auth-config |
AUTH_ENABLED |
Yes | Set to true to enable JWT validation. A startup warning is logged if unset in production. |
AUTH_REQUIRED_ROLES |
No | Comma-separated list of required app roles (e.g. IdentityAtlas.Read) |
ALLOWED_ORIGINS |
No | Comma-separated allowed CORS origins. Defaults to same-origin in production. The host names in these origins are also allowed hosts (see ALLOWED_HOSTS). |
ALLOWED_HOSTS |
No | Comma-separated host names users type to reach Identity Atlas (e.g. atlas.corp.example.com). While authentication is disabled, a request for a dotted host name that is not allowed is answered 421 Misdirected Request (protection against DNS rebinding), and the name is logged once with this hint. Always allowed without configuration: localhost, 127.0.0.1, [::1], any IP address, single-label names (web, atlas-vm) and .local names, plus the host of PUBLIC_BASE_URL, the hosts in ALLOWED_ORIGINS and Azure's WEBSITE_HOSTNAME. With authentication enabled the list is not enforced. /api/health and the crawler endpoints are never blocked. |
BEHIND_TLS |
No | Set to true when a TLS terminator (Caddy, nginx, Azure Front Door) sits in front. Enables HSTS/CSP upgrades and makes the Excel workbook export embed https:// URLs. Also trusts one proxy hop for the client address (see TRUST_PROXY_HOPS). |
TRUST_PROXY_HOPS |
No | Number of reverse proxies in front of the container whose X-Forwarded-For is trusted to identify the client (used for rate limiting and audit logs). Defaults to 1 when BEHIND_TLS=true or TRUST_PROXY=true, otherwise 0 (the connection address is the client). Set it to the real hop count, e.g. 2 for Front Door in front of App Service; set 0 to turn it off. |
PUBLIC_BASE_URL |
No | Authoritative public URL of the deployment (e.g. https://atlas.example.com). When set, the Excel workbook export embeds this instead of deriving the URL from request headers. Recommended for any deployment reached through a proxy, tunnel, or Azure — it removes any dependency on (spoofable) Host/X-Forwarded-* headers. |
TRUST_PROXY |
No | Set to true only when a trusted reverse proxy in front overwrites X-Forwarded-Host/X-Forwarded-Proto. Off by default, so forwarded headers are ignored when resolving the workbook export URL (prevents token exfiltration via header spoofing). Prefer PUBLIC_BASE_URL where possible. |
UPLOAD_MIN_FREE_BYTES |
No | Free space (bytes) that must remain on the upload volume after a crawler file upload; larger uploads are refused with 507. Default 1073741824 (1 GiB). The 1 GB per-file limit is unchanged. |
UPLOAD_CONFIG_QUOTA_BYTES |
No | Optional storage quota (bytes) per crawler configuration's upload folder; an upload that would exceed it is refused with 413. Default 0 (no quota). |
CRAWLER_AUDIT_LOG_MAX_ROWS |
No | Rows of crawler audit log kept per crawler (newest first); older rows are trimmed by the periodic maintenance job. Default 10000; 0 keeps everything. |
USE_MOCK |
No | Set to true to use mock data instead of PostgreSQL (local dev only) |
Endpoint Groups¶
| Group | Prefix | Description | Reference |
|---|---|---|---|
| Matrix & Permissions | /api/permissions, /api/access-package-groups, /api/*-columns |
Permission matrix data, column discovery, sync log | matrix.md |
| Entity Detail — Users | /api/users, /api/user/:id |
User list, attributes, memberships, history | entities.md |
| Entity Detail — Resources | /api/groups, /api/resources, /api/resources/:id |
Resource list, attributes, members, history | entities.md |
| Entity Detail — Business Roles | /api/access-package/:id |
Business role detail, assignments, reviews, requests | entities.md |
| Systems & Org hierarchy | /api/systems, /api/contexts/tree, /api/org-chart |
Connected systems and the org/context hierarchy | entities.md |
| Identities | /api/identities |
Identities + linked accounts; per-account analyst overrides | entities.md |
| Account Linking | /api/account-linking |
Account-linking dictionary config + run endpoints (admin.crawlers) |
entities.md |
| User Preferences | /api/preferences |
Per-user tab visibility | entities.md |
| Governance & Business Roles | /api/access-packages, /api/categories |
Business role list and category management | governance.md |
| Tags | /api/tags |
Tag CRUD and assignment | governance.md |
| Risk Scores | /api/risk-scores |
Risk scoring data and analyst overrides | risk-scores.md |
| Org Chart | /api/org-chart |
Manager hierarchy tree with risk propagation | risk-scores.md |
| Performance Metrics | /api/perf |
Request timing and SQL query breakdowns | entities.md |
Common Conventions¶
Pagination¶
Paginated endpoints accept limit and offset query parameters and return a total field:
Error Responses¶
All errors return a JSON body with a message field. SQL schema details are never exposed in error responses.
| HTTP Status | Meaning |
|---|---|
400 |
Bad request — invalid parameter value or body |
401 |
Missing or invalid JWT |
403 |
Valid JWT but missing required role |
404 |
Entity not found |
429 |
Rate limit exceeded |
500 |
Internal server error |
Version History Format¶
Endpoints that return version history (e.g. GET /api/user/:id/history) query the _history audit table. Each entry includes a changedAt timestamp and a diff object showing which columns changed from the previous version.