Certificate API — Integration Guide
This guide is for teams that want to request SSL certificates programmatically through Stanford's certificate provisioning API, rather than through the web UI.
1. Prerequisites
Before you can call the API, you need two things set up:
a. Set up a Keycloak API client
If your team doesn't already have one, request it:
- Open a ServiceNow ticket
- Assignment Group:
UIT Authentication and Collaboration - Request: API access / a Keycloak client for certificate automation (give your team name)
The team will generate a client_credentials-only Keycloak client for you (no interactive login—this is for machine-to-machine automation) and give you a client_id and client_secret.
Note: API clients are issued against Stanford's production Keycloak realm (stanford-oauth-prod) only. There is no separate development/UAT realm available for external teams at this time--see section 4 below.
b. Set up a KEYCLOAK_ID custom field on each NetDB node you need certs for
For every hostname (and every SAN, if requesting a multi-domain certificate) you want to request a certificate for, someone with edit access on that NetDB node needs to:
- Log in to https://netdb.stanford.edu/.
- Search for the node or domain where you want certificate issuance to be API-based and automated (for example,
med4.stanford.edu). - Edit it.
- Add a Custom Field labeled
KEYCLOAK_IDwith the value set to your client'sclient_id(for example,acs_linux_auth1, as provided by the UIT Authentication and Collaboration team).
This is how the API authorizes your client to request a certificate for that specific hostname—the API checks the caller's Keycloak client_id against this custom field on the node before allowing the request through. If it's missing or set to a different value, the request will be rejected with a message telling you exactly which node needs it and what value to set.
You do not need to provide a hostname list when requesting your Keycloak client--this NetDB step is the only place hostname authorization is configured, and it's fully self-service once your client exists.
2. Get a Bearer token
shell
TOKEN=$(curl -s -X POST \
"https://keycloak.svc.stanford.edu/auth/realms/stanford-oauth-dev/protocol/openid-connect/token" \
-d "grant_type=client_credentials" \
-d "client_id=<your_client_id>" \
-d "client_secret=<your_client_secret>" \
| python3 -c "import sys, json; print(json.load(sys.stdin)['access_token'])")Tokens are short-lived—request a fresh one for each session/script run rather than caching it long-term.
3. Build the request payload
At minimum, the payload needs:
shell
jq -Rs '{csr: .}' your-cert.csr > payload.json
Then add the required fields:
Python
import json
with open("payload.json") as f:
payload = json.load(f)
payload["contact_email"] = "you@stanford.edu"
payload["server_type"] = "Apache" # or Tomcat, Microsoft IIS, Java Web Server, RedHat Linux, Other
payload["duration"] = 199 # days
with open("payload.json", "w") as f:
json.dump(payload, f)A note on SANs: You only need to add a sans field if your CSR includes Subject Alternative Names beyond the primary Common Name (i.e., a multi-domain UCC certificate). For a standard single-domain certificate, leave sans out entirely—the API infers the domain from the CSR's CN. If you do include sans, it must exactly match what's actually encoded in the CSR itself, or the request will be rejected with a mismatch error telling you which hostnames are missing or extra.
4. Submit the request
shell
curl -s -X POST "https://certprovision-prod.iam.stanford.edu/api/submit" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d @payload.json \
| python3 -m json.toolAll API requests go directly to production. There is currently no separate UAT/test environment available for external teams to validate their integration against. We recommend testing your script against a low-stakes or throwaway hostname first, since your very first successful call will result in a real, issued certificate.
A successful submission returns something like:
JSON
{
"id": 38204,
"cn": "your-host.stanford.edu",
"cert_type": "normal",
"order_number": null,
"duration": 199,
"server_type": "Apache/ModSSL",
"async": true,
"backend": "acme"
}Certificate issuance happens asynchronously in the background—you'll be notified by email at the contact email address you provided once it's ready.
5. Retrieving your certificate
Besides the fulfillment email, every issued certificate is available for automated retrieval at:
https://certprovision-prod.iam.stanford.edu/cert/<your-hostname>
Available formats:
URL | Returns |
| Certificate with full chain — recommended for most servers (Apache/nginx) |
| Certificate only |
| Intermediate certificates only (CA chain, not your certificate) |
| Intermediate certificates only, in reverse order (root first) — for older server software that needs the chain in this specific order |
This is the same URL linked from the fulfillment email — you can poll it directly (e.g., on a cron schedule) rather than relying on parsing the email, which is useful if you want to automate detecting when a certificate has been renewed.
We do not currently offer a full ACME protocol endpoint with External Account Binding (EAB) for fully automated, certbot-driven renewal. This is in development for a future release.
6. Common error messages
| Message contains | Meaning | Fix |
|---|---|---|
has no KEYCLOAK_ID Custom Field set | The NetDB node isn't linked to your client yet | Add the KEYCLOAK_ID custom field per step 1b above |
has a KEYCLOAK_ID Custom Field set to '...', which does not match | The node is linked to a different client | Correct the KEYCLOAK_ID value, or use the client it's actually set to |
the Subject Alternative Names in your CSR do not match the hostnames you requested | Your sans field and your CSR's actual SAN extension disagree | Make sure sans (if present) exactly matches what's in the CSR, or drop sans if you don't need it |
Not authenticated | Missing or invalid Bearer token | Confirm your token hasn't expired and the Authorization header is set correctly |
Questions
Reach out via the UIT Authentication and Collaboration group or submit a Help ticket.
