Skip to content
Last updated

SDK Authentication

The SDK does not authenticate an end user itself. The issuer authenticates its user in its own backend, then gives the SDK a short-lived session through an issuer-controlled proxy.

Production SDK integrations use signed JWT client assertions. The issuer proxy signs every widget-session mint request with its private key, and Percents verifies that assertion with the issuer's registered JWKS. This is the required production authentication method; do not use a shared secret or issuer API token for this flow.

Trust Boundaries

Issuer host app and browser
  -> issuer proxy: opaque proxy session token
  -> Percents: no issuer credential and no widget token

Issuer proxy
  -> Percents: short-lived, CHG-scoped widget token

The browser and hosted iframe must never receive an issuer-wide Percents API token or the Percents widget token. The opaque proxy session token is meaningful only to the issuer proxy.

Session Flow

  1. The issuer backend authenticates the current user with its existing identity system.
  2. The issuer backend resolves that user or business to a persisted Percents cardholder group (chgId). Do not accept a client-side-supplied chgId.
  3. The issuer proxy obtains a short-lived widget token from Percents, scoped to that CHG, and stores it server-side.
  4. The proxy creates an opaque, expiring proxy session and returns its token, the proxy API URL, and the widget URL to the SDK.
  5. The hosted iframe sends its requests to the issuer proxy with the proxy-session token. The proxy validates the session, forwards only widget-allowed operations with the scoped widget token, and removes server-only data from responses.

Persist the issuer user/business-to-CHG mapping. Percents webhooks identify the CHG, so the issuer needs that durable mapping to route follow-up work or notifications correctly.

For integration setup and the session response shape, see the SDK Quickstart. For iframe message and session boundaries, see SDK Security and Sessions.

Production Mint Authentication

The issuer proxy authenticates itself to Percents by sending a signed JWT assertion with every widget-session mint request. The assertion is a short-lived proof that the issuer proxy controls its registered private key and is authorized to mint a session for one cardholder group.

Authentication Flow

Percents iframeIssuer JWKS endpointPercents APIIssuer proxyIssuer host app and browserPercents iframeIssuer JWKS endpointPercents APIIssuer proxyIssuer host app and browserRequest widget proxy session using issuer login sessionAuthenticate user and resolve CHGSign mint assertion with issuer private keyPOST widget session with assertion and chgIdFetch public key selected by kid (when needed)JWKS public keysVerify signature, issuer, audience, time, jti, and CHG ownershipShort-lived CHG-scoped widget tokenStore widget token and create opaque proxy sessionwidgetUrl, proxyApiBaseUrl, opaque proxySessionTokenMount iframe and provide proxy session tokenWidget request with opaque proxy session tokenAllowed widget request with server-side widget token
Percents iframeIssuer JWKS endpointPercents APIIssuer proxyIssuer host app and browserPercents iframeIssuer JWKS endpointPercents APIIssuer proxyIssuer host app and browserRequest widget proxy session using issuer login sessionAuthenticate user and resolve CHGSign mint assertion with issuer private keyPOST widget session with assertion and chgIdFetch public key selected by kid (when needed)JWKS public keysVerify signature, issuer, audience, time, jti, and CHG ownershipShort-lived CHG-scoped widget tokenStore widget token and create opaque proxy sessionwidgetUrl, proxyApiBaseUrl, opaque proxySessionTokenMount iframe and provide proxy session tokenWidget request with opaque proxy session tokenAllowed widget request with server-side widget token
  1. The issuer host app asks its own backend for a widget proxy session. Its existing issuer login session authenticates this request.
  2. The issuer proxy authenticates the user and resolves the user or business to a persisted Percents cardholder group (chgId). Never accept a client-side-supplied chgId as the source of truth.
  3. The proxy creates a new signed mint assertion using its private key. The private key stays in issuer-controlled server-side infrastructure.
  4. The proxy sends the assertion and chgId to Percents to mint a widget session.
  5. Percents selects the issuer's public key using the assertion's kid, retrieving the issuer's JWKS as needed.
  6. Percents validates the assertion's signature, algorithm, issuer, audience, expiry, issue time, unique ID, and ownership of the requested CHG.
  7. Percents returns a short-lived widget token scoped to that CHG and widget-safe operations. The proxy stores this token server-side.
  8. The proxy returns an opaque proxy-session token to the SDK. The browser and iframe use that token only with the issuer proxy; they never receive the signed assertion, private key, issuer API token, or Percents widget token.

Mint Request

The issuer proxy mints a Percents widget session with:

POST <percents-api-base-url>/api/v2/widget/session
Authorization: Bearer <signed-mint-assertion>
Content-Type: application/json

{
  "chgId": "chg_..."
}

<signed-mint-assertion> is an RS256 JSON Web Signature (JWS) carrying a JSON Web Token (JWT). It is sent only from the issuer proxy to Percents.

Assertion Fields

The following fields are required for every signed mint assertion:

LocationFieldValueWhy Percents validates it
Protected headeralgRS256Ensures Percents uses the configured asymmetric signing algorithm and never accepts an unexpected algorithm.
Protected headerkidIdentifier for a public key in the issuer's JWKSLets Percents select the correct public key and supports safe key rotation.
JWT claimissIssuer identifier supplied by Percents during onboardingIdentifies the issuer making the assertion. Percents derives the issuer from this verified claim; do not send a separate issuer identifier in the request body.
JWT claimchgIdThe Percents cardholder group being authorizedBinds the assertion to one CHG. It must exactly match the request body and belong to the issuer identified by iss.
JWT claimaudExact audience value supplied by Percents for this issuer and environmentIdentifies the intended recipient: the Percents SDK-session endpoint. It prevents an assertion for another API or environment from being reused here.
JWT claimiatTime the assertion was issuedAllows Percents to reject assertions that are too old.
JWT claimexpExpiration time, no more than five minutes after iatLimits the time in which a stolen assertion could be used.
JWT claimjtiA new, unique assertion ID, such as a UUIDAllows Percents to reject a replay of an assertion that has already been used.

Expected Audience

aud is the standard JWT audience claim defined in RFC 7519 section 4.1.3. It identifies the intended recipient of a token. In this flow, the recipient is the Percents SDK-session endpoint—not the issuer, the SDK, or the iframe.

Percents supplies the exact, environment-specific audience value during onboarding. The issuer proxy must include that exact value in every mint assertion, and Percents rejects an assertion with any other value. This prevents an assertion created for another API, customer integration, or environment from being accepted by the widget-session mint endpoint. This follows the JWT best practice to validate issuer and audience claims (RFC 8725 section 3.9).

Production Onboarding and Key Rotation

  1. Obtain the issuer identifier and expected audience from your Percents account manager.
  2. Generate and protect an RS256 private key in issuer-controlled server-side infrastructure. Do not expose it to a browser, mobile app, or client-side configuration.
  3. Publish the corresponding public key in a stable HTTPS JWKS endpoint, typically https://issuer.example.com/.well-known/jwks.json.
  4. Provide Percents with that JWKS URL. Percents uses it to verify assertions from the issuer proxy.
  5. When rotating keys, publish the new public key with a new kid before the proxy begins signing with its corresponding private key. Keep the prior public key available until all assertions signed with it have expired.

Percents resolves the public key selected by kid, verifies the signature and claims, rejects a jti that has already been used during the assertion's validity window, and confirms that the CHG belongs to the issuer identified by iss. Percents then returns a short-lived widget token restricted to that CHG and the widget-safe operations.

JWKS discovery supports signing-key rotation without sharing a secret or manually registering a new key.

Integration Requirements

  • Keep issuer API tokens, signing keys, and widget tokens in server-side infrastructure only.
  • Use an expiring, opaque proxy session token in the browser; validate it on every proxy request.
  • Allowlist only the widget routes the proxy needs. Do not turn the proxy into a general-purpose Percents API relay.
  • Enforce the server-resolved CHG on every proxied request and remove chgId from browser-visible responses.
  • Store proxy sessions and widget tokens in a shared, durable server-side store when using multiple proxy instances.
  • Restrict browser origins and iframe framing with appropriate CORS and CSP frame-ancestors configuration.