> ## Documentation Index
> Fetch the complete documentation index at: https://docs.etherfuse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Exchange a partner JWT

> OAuth 2.0 token endpoint ([RFC 6749 §3.2](https://www.rfc-editor.org/rfc/rfc6749#section-3.2)). Exchanges a partner-signed JWT for an Etherfuse access/refresh token pair, or refreshes an existing session.

Call this from your backend to provision a user ahead of a launch, or to prefetch a `refresh_token` that speeds up the launch redirect. Your backend signs a JWT with the key behind your registered JWKS and posts it here. To drop a user straight into the app in a browser, use [POST /auth/launch](/api-reference/authentication/launch-a-user-into-the-app) instead.

## Grant types

- `urn:ietf:params:oauth:grant-type:jwt-bearer` ([RFC 7523](https://www.rfc-editor.org/rfc/rfc7523)). Put the partner JWT in `assertion`.
- `refresh_token` ([RFC 6749 §6](https://www.rfc-editor.org/rfc/rfc6749#section-6)). Put a prior `refresh_token` in `refresh_token`.

## The JWT

Sign it with the key behind your registered JWKS (see [Sign a user JWT](/guides/jwt-authentication#sign-a-user-jwt) for full detail). Claims:

- **`iss`**: your registered issuer.
- **`sub`**: the person signing in; a UUID is _strongly recommended_ (for an individual customer it's the same value as `customerId` in the Ramp API). Must name a person, never a business: a business org id is rejected with `invalid_grant`, and a `sub` can't be reused as a business org id ([POST /ramp/organization](/api-reference/organizations/create-child-org) returns 409). A non-UUID `sub` still signs in, but can't be addressed through the Ramp API.
- **`aud`**: the token endpoint URL, `https://api.etherfuse.com/auth/token` (`https://api.sand.etherfuse.com/auth/token` in sandbox).
- **`scope`**: required. Names the flow the user may complete (see [User Launch Flows](/guides/user-launch-flows#scopes)); an unrecognized scope is rejected with `invalid_scope`.
- **`jti`** / **`nonce`**: a fresh value, unique per token, for replay protection. You can send it as `jti` (the standard JWT ID) or `nonce` (the standard OIDC claim).
- **`exp`, `iat`**: required; keep tokens short-lived.
- **`email`, `name`**: required; populate the user's profile. `picture` is optional.

This endpoint is unauthenticated: the signed JWT (or refresh token) is the credential. Do **not** send an API key.



## OpenAPI

````yaml /openapi.json post /auth/token
openapi: 3.1.0
info:
  title: Etherfuse FX API
  description: Partner-facing ramp API for onramps, offramps, swaps, and KYC.
  license:
    name: Proprietary
  version: 1.0.0
servers:
  - url: https://api.sand.etherfuse.com
    description: Sandbox
security:
  - ApiKeyAuth: []
tags:
  - name: Authentication
    description: >-
      Partner JWT authentication — exchange a JWT for an access token, or launch
      a user into the app.
  - name: Lookup
    description: >-
      Public reference data: exchange rates, stablebonds, bond costs, country
      codes.
  - name: Assets
    description: Rampable stablecoins and stablebonds available per blockchain.
  - name: Onboarding
    description: Hosted and programmatic customer onboarding.
  - name: Bank Accounts
    description: Register and retrieve customer bank accounts.
  - name: Quotes
    description: Price quotes for onramps, offramps, and swaps.
  - name: Orders
    description: Create, track, and manage ramp orders.
  - name: Swaps
    description: Crypto-to-crypto swaps.
  - name: Sponsored
    description: Token approvals for sponsored (gasless) offramps.
  - name: Customers
    description: Customer (child-organization) records.
  - name: Wallets
    description: Register and manage customer wallets.
  - name: KYC
    description: Submit and check customer KYC status.
  - name: Webhooks
    description: Event notification subscriptions.
  - name: Organizations
    description: Organization identity, child orgs, and partner fees.
paths:
  /auth/token:
    post:
      tags:
        - Authentication
      summary: Exchange a partner JWT
      description: >-
        OAuth 2.0 token endpoint ([RFC 6749
        §3.2](https://www.rfc-editor.org/rfc/rfc6749#section-3.2)). Exchanges a
        partner-signed JWT for an Etherfuse access/refresh token pair, or
        refreshes an existing session.


        Call this from your backend to provision a user ahead of a launch, or to
        prefetch a `refresh_token` that speeds up the launch redirect. Your
        backend signs a JWT with the key behind your registered JWKS and posts
        it here. To drop a user straight into the app in a browser, use [POST
        /auth/launch](/api-reference/authentication/launch-a-user-into-the-app)
        instead.


        ## Grant types


        - `urn:ietf:params:oauth:grant-type:jwt-bearer` ([RFC
        7523](https://www.rfc-editor.org/rfc/rfc7523)). Put the partner JWT in
        `assertion`.

        - `refresh_token` ([RFC 6749
        §6](https://www.rfc-editor.org/rfc/rfc6749#section-6)). Put a prior
        `refresh_token` in `refresh_token`.


        ## The JWT


        Sign it with the key behind your registered JWKS (see [Sign a user
        JWT](/guides/jwt-authentication#sign-a-user-jwt) for full detail).
        Claims:


        - **`iss`**: your registered issuer.

        - **`sub`**: the person signing in; a UUID is _strongly recommended_
        (for an individual customer it's the same value as `customerId` in the
        Ramp API). Must name a person, never a business: a business org id is
        rejected with `invalid_grant`, and a `sub` can't be reused as a business
        org id ([POST
        /ramp/organization](/api-reference/organizations/create-child-org)
        returns 409). A non-UUID `sub` still signs in, but can't be addressed
        through the Ramp API.

        - **`aud`**: the token endpoint URL,
        `https://api.etherfuse.com/auth/token`
        (`https://api.sand.etherfuse.com/auth/token` in sandbox).

        - **`scope`**: required. Names the flow the user may complete (see [User
        Launch Flows](/guides/user-launch-flows#scopes)); an unrecognized scope
        is rejected with `invalid_scope`.

        - **`jti`** / **`nonce`**: a fresh value, unique per token, for replay
        protection. You can send it as `jti` (the standard JWT ID) or `nonce`
        (the standard OIDC claim).

        - **`exp`, `iat`**: required; keep tokens short-lived.

        - **`email`, `name`**: required; populate the user's profile. `picture`
        is optional.


        This endpoint is unauthenticated: the signed JWT (or refresh token) is
        the credential. Do **not** send an API key.
      operationId: auth_token
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AuthTokenRequest'
          application/json:
            schema:
              $ref: '#/components/schemas/AuthTokenRequest'
      responses:
        '200':
          description: A bearer access token and refresh token
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthTokenResponse'
        '400':
          description: >-
            OAuth error: `invalid_request`, `invalid_grant`, `invalid_scope`, or
            `unsupported_grant_type` ([RFC 6749
            §5.2](https://www.rfc-editor.org/rfc/rfc6749#section-5.2))
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthErrorResponse'
      security: []
components:
  schemas:
    AuthTokenRequest:
      type: object
      required:
        - grant_type
      properties:
        grant_type:
          type: string
          enum:
            - urn:ietf:params:oauth:grant-type:jwt-bearer
            - refresh_token
          description: The OAuth 2.0 grant type.
        assertion:
          type: string
          description: >-
            The partner-signed JWT. Required when `grant_type` is
            `urn:ietf:params:oauth:grant-type:jwt-bearer`.
        refresh_token:
          type: string
          description: >-
            A refresh token from a prior exchange. Required when `grant_type` is
            `refresh_token`.
      example:
        grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer
        assertion: eyJhbGciOiJSUzI1NiIsImtpZCI6Imt...
    AuthTokenResponse:
      type: object
      required:
        - access_token
        - token_type
        - expires_in
        - refresh_token
      properties:
        access_token:
          type: string
          description: >-
            Bearer token for the Ramp API. Send it as `Authorization: Bearer
            <access_token>`.
        token_type:
          type: string
          example: Bearer
        expires_in:
          type: integer
          description: Access token lifetime, in seconds.
          example: 3600
        refresh_token:
          type: string
          description: >-
            Use with the `refresh_token` grant to obtain a fresh access token
            without re-signing a JWT.
        scope:
          type: string
          description: >-
            The granted scope, echoed from the JWT's `scope` claim. Omitted for
            unrestricted (non-partner) sessions.
    AuthErrorResponse:
      type: object
      description: >-
        OAuth 2.0 error response ([RFC 6749
        §5.2](https://www.rfc-editor.org/rfc/rfc6749#section-5.2)).
      required:
        - error
      properties:
        error:
          type: string
          enum:
            - invalid_request
            - invalid_client
            - invalid_grant
            - invalid_scope
            - unauthorized_client
            - unsupported_grant_type
            - server_error
        error_description:
          type: string
        error_uri:
          type: string
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: API key sent in the Authorization header.

````