Nimbu Developer Docs

OpenID Connect ("Login with Nimbu")

Use a Nimbu site's customer accounts as an OpenID Connect identity provider: discovery, the authorization code flow, ID tokens, userinfo claims and the storefront consent screen.

A Nimbu site can act as an OpenID Connect (OIDC) provider for its customers. Another application, or another Nimbu site, can then offer "Login with your site": the customer signs in on your storefront, approves the request, and the relying party receives an ID token plus profile claims.

This page covers customer login. For OAuth in general (scopes, refresh tokens, password grant) see Authentication. MCP connectors use a separate admin-user flow, documented under MCP.

Enable the provider

OIDC is off by default and is a per-site setting that Nimbu support turns on ("Enable OpenID Connect Provider"). While it is off, the discovery document returns 404 and any authorization request that includes the openid scope fails with invalid_scope.

Register a client

In the backoffice of the providing site, go to Settings → Apps → New OAuth 2 app:

  • Authorization Callback URL: the relying party's redirect URI. Redirect URIs are matched exactly.
  • Confidential: leave on for server-side clients that can keep the secret. Public clients (off) must use PKCE and always see the consent screen.
  • Customer scopes: add openid, plus email, profile and/or full_profile as needed. Scopes the client requests but that are not listed here are silently dropped.

The app's key is the client_id; its secret is the client_secret.

Discovery

Each site publishes its configuration on its primary domain:

curl "https://www.example.com/.well-known/openid-configuration"
{
  "issuer": "https://www.example.com",
  "authorization_endpoint": "https://www.example.com/oauth2/authorize",
  "token_endpoint": "https://api.nimbu.io/oauth2/tokens",
  "userinfo_endpoint": "https://api.nimbu.io/oauth2/userinfo",
  "jwks_uri": "https://api.nimbu.io/oauth2/certs",
  "scopes_supported": ["openid", "email", "profile", "full_profile"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code"],
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"],
  "claims_parameter_supported": false,
  "claims_supported": [
    "sub", "iss", "aud", "iat", "name", "family_name", "given_name", "locale", "email", "email_verified",
    "https://www.example.com/loyalty_number"
  ]
}
  • The issuer is https:// plus the site's primary domain. The authorize endpoint lives on the storefront; token, userinfo and keys live on the API host.
  • Only the authorization code flow is supported, and ID tokens are signed with RS256.
  • claims_supported lists one extra claim per customer custom field, named <issuer>/<field_name>.

The flow

1. Authorize. Send the customer to the storefront:

https://www.example.com/oauth2/authorize
  ?response_type=code
  &client_id=CLIENT_ID
  &redirect_uri=https%3A%2F%2Fapp.example.org%2Fcallback
  &scope=openid%20email%20profile
  &state=RANDOM_STATE
  &nonce=RANDOM_NONCE
  &code_challenge=BASE64URL_SHA256_OF_VERIFIER
  &code_challenge_method=S256
  • Only response_type=code is accepted.
  • PKCE: only S256. Public clients must send a code_challenge; confidential clients may, and once a challenge is sent the verifier is always required at the token endpoint.
  • redirect_uri must match a registered URI. It may be omitted only when the app has exactly one.

If the customer is not signed in, Nimbu asks them to log in first. They then see the consent page, rendered from your theme's templates/customers/oauth2_consent.liquid (see Customer login for the template and the {% oauth2_consent_form %} tag). Confidential apps that the customer already approved for the same scopes skip the consent screen. On approval the customer is redirected to redirect_uri?code=…&state=…; on denial with error=access_denied.

2. Exchange the code.

curl -X POST "https://api.nimbu.io/oauth2/tokens" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code="$CODE" \
  -d redirect_uri="https://app.example.org/callback" \
  -d code_verifier="$VERIFIER"
{
  "access_token": "eyJ…",
  "token_type": "bearer",
  "expires_in": 1800,
  "refresh_token": "…",
  "scope": "openid email profile",
  "id_token": "eyJ…"
}
  • Send the client secret with HTTP Basic auth or as client_secret in the body. Public clients send only client_id.
  • redirect_uri must be identical to the one used in the authorize request.
  • id_token is only returned when openid was granted.
  • Access tokens last 30 minutes. Refresh with grant_type=refresh_token; customer refresh tokens are not rotated, so keep using the same one.

3. Validate the ID token. Fetch the keys from https://api.nimbu.io/oauth2/certs and pick the key by the token's kid (the set also contains keys used for MCP tokens). The ID token holds iss (the site issuer), sub (the customer id), aud (your client_id), iat, exp (one hour) and nonce when you sent one. Profile data is not in the ID token; read it from userinfo.

4. Read userinfo.

curl "https://api.nimbu.io/oauth2/userinfo" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
{
  "sub": "66f0a1b2c3d4e5f60718293a",
  "email": "jane@example.com",
  "email_verified": true,
  "name": "Jane Doe",
  "given_name": "Jane",
  "family_name": "Doe",
  "locale": "nl",
  "https://www.example.com/loyalty_number": "A-1042"
}

GET and POST both work. Claims depend on the granted scopes:

ScopeClaims
openidsub (customer id)
emailemail, email_verified (true once the customer confirmed their address)
profilename, given_name, family_name, locale
full_profile<issuer>/<field_name> for every customer custom field, with the value as the REST API serializes it

Using another Nimbu site as the relying party

A second Nimbu site can log its customers in with the first site's accounts, without code:

  1. On the providing site, create an OAuth 2 app as above with customer scopes openid, email, profile, and set the callback URL to https://<relying-site-domain>/auth/nimbu/callback.
  2. On the relying site, go to Settings → Push & Integrations and enable the Login with Nimbu integration:
    • Issuer: the providing site's primary domain.
    • Client ID / Client secret: from the app in step 1.
    • Match email: link to an existing customer with the same email address when the account is not linked yet.
    • Autoregister: create a customer when none is found (implies email matching). Skip confirmation lets those customers skip email confirmation.

The relying site requests openid email profile and uses discovery on the issuer. The login button and callback handling in the theme are covered in Customer login.

Any standards-compliant OIDC client library works the same way: point it at the issuer, let it read the discovery document, and use the authorization code flow with PKCE.

On this page