A Private API Reference Without Building a Login

·4 min read

api-docsopenapissosecurity

Most API references are public, and should be. But a lot of them aren't: the partner API only three companies integrate with, the internal platform API, the v2 you're piloting with a handful of customers. The OpenAPI document exists. The question is who gets to read it.

That question tends to get answered in a hurry, and the answer usually has a hole in it.

The usual answers

A shared password on the docs site. Basic auth in front of a static build. It takes ten minutes, and it's a credential that never rotates, gets pasted into Slack, and survives every departure. Nobody can tell you who has read the docs, because everybody is the same user.

The VPN. Fine for staff, useless for partners, and it quietly turns "can read the API reference" into "can reach the internal network" — a much bigger grant than anyone meant to make.

The docs vendor's own accounts. Now readers have a second login, and you have a second user directory to keep in sync with the first. When someone leaves, you remember to remove them from your identity provider. Do you remember the docs tool?

Unlisted URLs. Security by obscurity, until a link ends up in a support ticket, a browser history sync, or a search engine.

Where the gate usually leaks

Even when the HTML is behind a login, a few things tend to stay out in the open.

The document itself. The rendered page is protected, but the reference loads its data from /openapi.json — and that path often isn't. Anyone who guesses it gets every endpoint, schema, and example, which is the whole point of the reference anyway.

The renderer's CDN. Many reference renderers are loaded from a public CDN. Every reader's browser then tells that third party who's reading, from where. For internal documentation read by employees in the EU, that's a data transfer you'd have to account for.

The origin. If the reference is served from the same host as your application, customer-supplied content — descriptions, examples, markdown in the spec — is rendered on the origin that holds your users' session cookies. A spec isn't usually hostile, but it's rarely written with that in mind either.

Gating on the login you already have

The better shape is to stop treating documentation access as its own problem. You already decide who can sign in: your company's Okta or Entra ID for staff, a sign-up flow for partners. A private reference should ask exactly that question and nothing else.

Concretely, that means:

  • No separate accounts. A reader signs in through the same connections your users do. Remove someone from the directory and they can no longer sign in to the reference either.
  • Access is a configuration, not a list. "Staff only" is "only the enterprise connection is enabled." "Partners" is "a connection partners can sign up through." There's no reader list to maintain.
  • The document follows the same rule as the page. An unauthenticated request for openapi.json gets nothing.
  • The reference lives on its own origin, away from session cookies, and its renderer is served from there too.

How this works in AuthAction

In AuthAction, a reference is an API Docs application. You create it with a name, publish an OpenAPI 3 or Swagger 2 JSON document, and choose its visibility.

Publishing happens in your browser or your pipeline — AuthAction never fetches the document, so a spec that only exists on an internal host is fine. From CI, it's one call to the Management API after your build produces the spec:

jq -n --slurpfile spec openapi.json '{docsSpecDocument: $spec[0]}' |
  curl -X PATCH "https://acme.eu.authaction.com/api/v1/applications/$DOCS_APP_ID" \
    -H "Authorization: Bearer $MANAGEMENT_API_TOKEN" \
    -H 'Content-Type: application/json' \
    --data @-

The reference is live immediately at https://acme--docs.eu.authaction.com/<client-id> — deliberately a different host from acme.eu.authaction.com, which holds the login session. To serve it as docs.acme.com, add a custom domain, choose API reference, and point a CNAME at your tenant.

Set it to private, and the application's Connections tab decides who can read it. An unauthenticated reader is sent through your hosted login and back to the reference; the document behind it is withheld until they've signed in.

What to check before you ship it

Which connections are enabled. This is the whole access policy for a private reference, so read it as one. A password connection that allows sign-up means anyone who registers can read your docs — right for a partner portal, wrong for an internal API.

What's actually in the spec. Internal hostnames, example tokens that turn out to be real, endpoints marked "do not use." A private reference narrows who reads these; it doesn't make them a good idea.

Where the old copy lives. If the reference used to be behind a shared password somewhere, take that version down. Two copies means two policies, and the weaker one wins.

The setup, including custom domains and publishing from CI, is in the Hosted API Reference guide.


Private API references, on the free tier

Publish an OpenAPI document as a hosted reference, public or behind the login you already run. Push it from CI and serve it on your own domain.

Free, unlimited users. No credit card required.