- Device completion — a backend binds a pending RFC 8628 device grant to an authenticated user, completing the CLI authentication flow without a second browser redirect.
- Remote signer session exchange — a short-lived access token is exchanged for a long-lived opaque remote signer session token (
pmth_*) scoped tosign:job. - Clearinghouse signer mint (Option A) — M2M client credentials with
sign:mint_user_tokenscope mints a user-scoped signer JWT and allowance data in a single call without a prior Builder API user-token step.
POST {issuer}/token) and the same grant_type, but with different resource values. Operation 3 uses client_credentials grant type.
Common parameters (operations 1 & 2)
All RFC 8693 token exchange requests:
Authentication: M2M HTTP Basic auth (
Authorization: Basic base64(m2m_id:m2m_secret)) is required for all token exchange calls.
Device completion (RFC 8693 + RFC 8628)
Use this operation in the NaaP / Option B flow: after the user authenticates at your backend, call the token endpoint to bind the pending device grant. The polling CLI receives its access token on the next poll.Prerequisites
- A confidential M2M client (
m2m_…) withdevice:approveorusers:tokenscope. device_third_party_initiate_loginenabled on the public client.- A user-scoped JWT for the public
app_…client (minted via User tokens).
Flow
Request
resource format: urn:pmth:device_code:<user_code> — use the user_code (e.g. ABCD-EFGH), not the device_code. PymtHouse normalizes the code before lookup.
Subject token requirements
Thesubject_token must be:
- A valid JWT issued by this PymtHouse issuer (signature verified against
{issuer}/jwks). - Issued to the public
app_…client for the same app (client_idorazpclaim = public client id). - Not expired.
allowed_scopes must include device:approve or users:token.
Response
Signer session exchange
Use this operation to exchange a short-lived user access token for a long-lived opaque remote signer session token (pmth_*).
Prerequisites
- HTTP Basic auth with the confidential M2M client (
m2m_…and secret). - The M2M client’s
allowed_scopesmust includeusers:token. - The
subject_tokenmust already containsign:jobscope.
Subject token binding
Thesubject_token must be a JWT from this issuer whose client_id or azp is either:
- The public
app_…client for the same developer app as the authenticating M2M client (typical after interactive login or Builder user-token mint), or - The same M2M
client_idas the request (legacyclient_credentialsaccess token used assubject_token).
Request
resource, or set resource to the issuer URL ({issuer}) if your client always sends a resource indicator (RFC 8707).
Response
Clearinghouse signer mint (Option A)
M2M clients withsign:mint_user_token scope (automatically added when the public client has sign:job) can mint a user-scoped signer JWT and receive allowance balance information in a single client_credentials call. This avoids the separate Builder API user-token step.
Request
Response
sign:mint_user_token is automatically granted to M2M clients when the public sibling client has sign:job in its allowed_scopes. No manual scope configuration is required.Error responses
Key design decisions
- Single token endpoint for all exchange types. Routing device completion, signer session exchange, and signer JWT mint through
POST {issuer}/tokenkeeps the public surface minimal and consistent with RFC standards. resourceas the dispatch discriminator.urn:pmth:device_code:<user_code>signals device completion; absence or the issuer URL routes to signer session exchange.- Binding is a side-effect, not the primary response. The CLI polls the standard device code endpoint rather than a proprietary callback, keeping device polling logic independent of the Option B backend.
- Option A (
sign:mint_user_token) minimizes round trips for clearinghouse integrators — one call returns both the signer JWT and the user’s current balance.
Implementation tasks
- For device completion: mint the user JWT via the Builder API before calling the token exchange.
- Validate that your backend stores the
user_codefrom the device code response and passes it verbatim to theresourceparameter. - For signer session exchange, verify the
subject_tokencontainssign:jobbefore calling. - For Option A: ensure the M2M client has
sign:mint_user_tokeninallowed_scopes(automatically derived from public client’ssign:job). - Check
balanceUsdMicrosfrom the Option A response to gate access before forwarding to the DMZ. - Do not retry a device completion exchange with the same
user_codeafter success; the grant has already been bound. - After obtaining a signer session or signer JWT, forward it to the remote signer DMZ — see Signer routing.