Use NuPaaS as an IdP — NuPaaS Docs
Identity & access

Use NuPaaS as an IdP

NuPaaS is an OpenID Provider. Register your internal app as a client, and its users sign in with their NuPaaS account — no second password store, and offboarding in NuPaaS ends access in your app.

What this is

Every organization has its own authorization server: its own issuer, its own discovery document, its own set of registered clients. A client belongs to exactly one organization, so a redirect URI registered in one organization cannot be used against another.

Manage clients at /orgs/<org>/settings/sso, under “Your OAuth / OIDC clients”. Registration is self-service — no support ticket, and no operator involvement.

Register a client

1Give it a display name you will recognise in the list.
2Add one redirect URI per line. These are matched exactly at authorization time — see below.
3Choose scopes. openid is required; email and profile are the usual set.
4Save, and copy the client secret immediately. It is shown once. NuPaaS stores a hash, so neither you nor we can read it back.

Endpoints

The discovery document is the source of truth. Point your client at it and it will read the rest:

https://authend.<org>.<platform-domain>/o/<organizationId>/.well-known/openid-configuration

Replace <organizationId> with your organization's id, shown beside the discovery URL on the settings page — the document you copy there is already the correct one.

ParameterTypeDescription
issuerstringYour organization's issuer identifier. A token's `iss` must equal this.
authorization_endpointurlWhere the browser is sent to sign in. Authorization code flow only.
token_endpointurlExchanges an authorization code for tokens. Client authentication is required (a client secret, or PKCE for public clients).
jwks_uriurlPublic keys for verifying an id_token's signature. Cache it; do not fetch per request.
userinfo_endpointurlReturns the same claims as the id_token, for an access token.

Redirect URIs

A redirect URI is the security boundary of the authorization code flow: a URI that is validated loosely at registration and matched loosely at authorize time delivers a code to an attacker's endpoint. NuPaaS therefore validates at registration and matches byte-for-byte at authorization.

A URI is accepted only when it is:

  • absolute — a scheme and a host are both required;
  • https, with one exception: http://localhost and http://127.0.0.1 are allowed, because local development genuinely needs them;
  • free of wildcards;
  • free of fragments.

Scopes

ParameterTypeDescription
openidrequiredRequests an id_token. Without it this is a plain OAuth flow and no identity claims are returned.
emailoptionalAdds the email address and whether it is verified.
profileoptionalAdds the display name.

Claims

The id_token and the userinfo endpoint return the same set. Every claim below is emitted only when the value is present — a user with no selected organization carries no organization claims at all, rather than claims with empty strings.

ParameterTypeDescription
substringStable user identifier. Use this as the primary key for the user in your app; it does not change when an email does.
emailstringPresent when the `email` scope is granted.
email_verifiedbooleanPresent alongside `email`.
namestringDisplay name. Present when the `profile` scope is granted.
organization_idstringThe organization the user signed in to. Emitted with the other two organization claims, or not at all.
org_slugstringThe organization's URL slug.
org_rolestringThe user's role within that organization: `owner`, `admin`, `member` or `viewer`, or the id of a custom organization role.
groupsstring[]The organization slug, as a single-element array. This is a published contract consumed by git host auto-membership — do not treat it as a general-purpose group list.
platform_rolestringPresent only when the user holds a NuPaaS platform grant. ADVISORY ONLY — see below.

Rotate a secret

Rotating issues a new secret and leaves the outgoing one working for a bounded window — 24 hours — so you can redeploy without an outage. The window's end is shown in the panel when you rotate; both secrets authenticate at the token endpoint until it closes, and only the new one after.

If the superseded secret is believed compromised rather than merely superseded, use Revoke superseded to close the window immediately. Rotation never deletes a client: disabling is reversible and keeps the audit trail.

Worked example

1 — Register the client (settings page), then exchange the code
# Your app sends the browser here:
#   https://authend.<org>.<domain>/o/<organizationId>/oauth/authorize
#     ?response_type=code
#     &client_id=<client id>
#     &redirect_uri=https://app.example.com/callback
#     &scope=openid%20email%20profile
#     &state=<opaque, verified on return>
#
# The user signs in, and the browser comes back to:
#   https://app.example.com/callback?code=<code>&state=<state>

# 2 — Exchange the code. The code is single-use; a second exchange fails.
curl -sS -X POST "https://authend.<org>.<domain>/o/<organizationId>/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=<code>" \
  -d "redirect_uri=https://app.example.com/callback" \
  -d "client_id=<client id>" \
  -d "client_secret=<client secret>"

Verify the id_token against the jwks_uri from discovery, check iss, aud, exp and the nonce you sent, then key the user by sub.