> For the complete documentation index, see [llms.txt](https://docs.peakcommerce.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.peakcommerce.com/integrations/identity-and-auth/customer-portal-single-sign-on-signed-jwt.md).

# Customer Portal Single Sign-On (Signed JWT)

Let your customers move from your own product into the PeakCommerce customer portal **already signed in** — no second login. Your application mints a short-lived, signed token for the customer and redirects them to the portal, where PeakCommerce validates the token and establishes their session.

This is one of two ways to set up customer-portal SSO. If you already run an identity provider, see [Connect to an OpenID Connect Identity Provider](/integrations/identity-and-auth/connect-to-openid-connect-identity-provider.md). The **signed-JWT handoff** described here is the simplest option when you just want to hand off an already-authenticated customer from your own app.

> **Scope:** This covers your **end-customers** signing in to the customer portal. It does not change staff or administrator sign-in.

### How it works

1. Your customer clicks a link in your product.
2. Your application mints a JWT for that customer, signs it, and redirects the customer to the portal endpoint with the token.
3. PeakCommerce validates the token and signs the customer into the portal, on the page you linked to.

Because the customer was already authenticated in your product, the hand-off is silent.

### What PeakCommerce provides

Ask PeakCommerce to enable the signed-JWT handoff for your tenant. You will receive, **per environment**:

* **Portal SSO endpoint** — `https://<your-portal-domain>/api/auth/jwt/start`
* **Signing secret** — a shared HS256 secret, delivered over a secure channel. Keep it server-side; never expose it to the browser or commit it to source control.
* **Audience** — the value your token's `aud` claim must equal (typically your portal domain).

You choose your own **issuer** identifier (the `iss` claim) and share it with PeakCommerce so it can be validated.

### Mint the token

Sign a JSON Web Token with **HS256**, using the shared secret as the signing key (as a literal string). Include these claims:

| Claim                 | Required    | Notes                                                                                                                                                                                                               |
| --------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `email`               | Yes         | Identity key — must match the customer's email in PeakCommerce.                                                                                                                                                     |
| `aud`                 | Yes         | Must equal the **Audience** value above (exact match, no trailing slash).                                                                                                                                           |
| `iss`                 | Yes         | Your issuer identifier.                                                                                                                                                                                             |
| `iat` / `exp`         | Yes         | Issued-at and expiry. Keep the lifetime short (for example, 5 minutes).                                                                                                                                             |
| `jti`                 | Yes         | A unique token id — enforced **single-use** to prevent replay.                                                                                                                                                      |
| `external_account_id` | Recommended | Your billing account reference for the customer — the **Zuora Account ID or the account number**. Used to show the customer's subscriptions, invoices, and payments. Without it a new customer has no account data. |
| `external_contact_id` | Optional    | Contact reference, if you track one separately.                                                                                                                                                                     |
| `profile_id`          | Optional    | The portal profile to assign a brand-new customer (see [Access levels](#access-levels)). Must be a customer profile in your tenant; otherwise the default is used.                                                  |
| `name`                | Optional    | Customer display name.                                                                                                                                                                                              |

### Redirect the customer

Send the customer to the portal endpoint with the token. **POST is recommended** (it keeps the token out of URLs and logs):

```
POST https://<your-portal-domain>/api/auth/jwt/start
     token=<the JWT>
```

Or, for a simple link, use GET:

```
https://<your-portal-domain>/api/auth/jwt/start?token=<the JWT>
```

Add `returnTo=<relative path>` (for example `returnTo=/customer/subscriptions`) to deep-link to a specific page after sign-in.

> **Use the exact path `/api/auth/jwt/start`, and send the JWT in the `token` parameter.** It is not `/login/callback` — that path belongs to the OpenID Connect option.

### Access levels

New customers are granted access **automatically on first sign-in** — no manual approval step.

* **Default:** a new customer gets your **Customer Default** profile — full self-service (view subscriptions and invoices, place orders, update profile, manage payment methods, and contact support).
* **Choosing a profile:** to place a customer in a different profile — for example a read-only cohort — include that profile's id in the `profile_id` claim. You manage your profiles, and read their ids, in the PeakCommerce admin **Profiles** screen. Adding a cohort is just creating a profile and using its id.

A returning customer keeps whatever profile they already have — `profile_id` only applies the first time a customer is created.

### Account linking

`external_account_id` can be **either** the Zuora **Account ID** (the 32-character internal id) **or** the human-readable **account number** (for example `C-00001534`). PeakCommerce accepts both and resolves the number to the Account ID for you, then uses it to pull the customer's subscriptions, invoices, and payments. Both identifiers are available from Zuora: the Account ID is the `Id` field on the Account object, and the account number is `AccountNumber`.

### Returning to your application

Because the customer arrived via SSO, **your application owns the master session** — a portal-local "log out" would be misleading, since signing out of the portal alone would leave the customer still signed in to your product. When a **return URL** is configured for your tenant's SSO setup, the portal handles this for you: the header's logout control is replaced with a persistent **"Back to \<your application>"** link that takes the customer straight back to your product, and sign-out becomes SSO-aware rather than portal-local.

The return URL is configured operator-side, per tenant (it must be an HTTPS URL) — contact your PeakCommerce representative to set or change it. If no return URL is configured, the portal keeps its standard logout control.

### Security

* The signing secret can mint a sign-in for **any** customer. Keep it server-side only, never in client code or source control, and rotate it if it may have been exposed.
* PeakCommerce issues a **separate secret per environment**.
* Every token is validated for signature, audience, issuer, expiry, and single-use (`jti`) before a session is created.

### Test the connection

1. An existing customer clicks the link and lands in the portal, signed in, viewing their subscriptions.
2. A brand-new customer clicks the link and is granted access automatically.
3. A `returnTo` link takes the customer to the intended page after sign-in.
4. If a return URL is configured, the portal header shows the **Back** link (not a logout icon) and it lands the customer back in your application.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.peakcommerce.com/integrations/identity-and-auth/customer-portal-single-sign-on-signed-jwt.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
