Skip to main content
Work with Tesouro’s Implementation team to get set up with access to our environment and configure your branding.

Branding options

For white label and widget implementations, you can customize the following parameters for your brand:
  • Main color
  • Logo (large)
  • Logo (small)

Authentication

The first steps for integrating with Tesouro are to:
  1. Activate your developer account
  2. Receive your API access key credentials
  3. Create and authenticate your first JSON Web Token (JWT) to Tesouro.

Access your organization’s API access key credentials

Your organization’s API access key and secret are created by Tesouro and shared with you. To receive access:
  1. Have your designated team lead submit your access request here (external site managed by Tesouro)
  2. Tesouro will email you an API access key and secret that will require passwordless authentication via email address.

Create and authenticate your JWT

Create a JWT, then add it to the header of your call to query the Tesouro Sandbox environment
Authentication Request
POST /openid/connect/token
  curl --location 'https://api.sandbox.tesouro.com/openid/connect/token' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data-urlencode 'grant_type=client_credentials' \
    --data-urlencode 'client_id=CLIENT_ID' \
    --data-urlencode 'client_secret=CLIENT_SECRET'
Authentication Request
{
  "access_token": "efJhbGcifiJv4zI1NiIsInR5cCI6IkpXVCJ9.eyJ0X2FwaWtleSI6Iml1bm5p9EtYTk1IYjNudGJIZTRZYVVER9JiTT0iLCJ0X29yZ2lkIjoiZWRhMGU5MmItMmRkNS00ZWE2LWI0YjgtZTIyYmRiODVjYjVjIiwidF9wcmVzaWQiOiIwOTUyZmEwMi1hOWUzLTRjMjgtYjEyOC00MTIxODY5MzEwZTQiLCJzY29wZXMiOiJ7fSIsIm5iZiI6MTY4OTk2MjQzNywiZXhwIjoxNjg5OTY0MjM3LCJpYXQiOjE2ODk5NjI0MzcsImlzcyI6Imh0dHBzOi8vYXV0aC50ZXNvdXJvLmNvbSIsImF1ZCI6Imh0dHBzOi8vdGVzb3Vyby5jb20ifQ.M7o-I9Rdb3fjOXsoAmR5NSSbF_Vs2WdHWpenstDLn7M",
  "token_type": "Bearer",
  "expires_in": 3600
}
Example Request
POST https://api.business-banking.app/api/embedded
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ADD_TOKEN_HERE" \
  -d '{
      "query": "query bankAccounts($input: BankAccountQueryInput!) {
          bankAccounts(input: $input) {
            items {
              bankAccountBalance
              id
              bankAccountNickname
              bankAccountNumber
              routingNumber
            }
          }
        }",
      "variables": {
        "input": {
          "where": {"id": {"eq": "eaae8b39-e86b-4cce-9fa3-68f633c08ab6"}},
          "paging": {
            "skip": 0,
            "take": 10
          }
        }
      }
    }' \
  https://api.sandbox.business-banking.app/api/embedded
Example Response
{
  "data": {
    "organization": {
      "id": "66f41f51-cc83-440b-948f-afe3d4c57406",
      "businessName": "Tesouro Docs Playground (Sandbox)"
    }
  }
}
For production, use https://api.business-banking.app instead of https://api.sandbox.business-banking.app with production credentials

Token Exchange for User Impersonation

For seamless widget and API experiences, Tesouro supports OAuth 2.0 Token Exchange (RFC 8693). This allows your application to impersonate users on the Tesouro platform by exchanging a user JWT for an access token.
Token Exchange Request
POST /openid/connect/token
curl --location 'https://api.sandbox.tesouro.com/openid/connect/token' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
  --data-urlencode 'client_id=CLIENT_ID' \
  --data-urlencode 'client_secret=CLIENT_SECRET' \
  --data-urlencode 'subject_token=USER_JWT_TOKEN' \
  --data-urlencode 'subject_token_type=urn:ietf:params:oauth:token-type:access_token'
Token Exchange Response
{
  "access_token": "efJhbGcifiJv4zI1NiIsInR5cCI6IkpXVCJ9...",
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token",
  "token_type": "Bearer",
  "expires_in": 3600
}
Subject Token Requirements: Your JWT must include both the user’s unique identifier in the sub claim and the user’s email address in the email claim. The returned access token contains RFC 8693 delegation claims indicating it’s an impersonated token.
Security: Users can only be impersonated within their assigned application context. Cross-application impersonation is prevented for security.

Widget Authentication

For embedded widgets, your backend generates a widget token that securely wraps the user’s identity and OAuth credentials using JWE (RFC 7516). This token contains an RFC 8693 token exchange payload that is provided to the widget on the frontend. What You Provide:
  • Backend code to generate an encrypted JWE widget token
  • The token contains user identity (ID and email) and OAuth credentials
  • You control token expiration based on your security requirements
Widget Token Generation
  async function createWidgetToken(userId: string, userEmail: string) {
    const clientId = process.env.TESOURO_CLIENT_ID;
    const clientSecret = process.env.TESOURO_CLIENT_SECRET;
    const sharedSecret = process.env.TESOURO_WIDGET_SECRET; // 32 bytes

    const now = Math.floor(Date.now() / 1000);
    const secretKey = new TextEncoder().encode(sharedSecret);

    // Step 1: Create subject token (user identity)
    const subjectTokenPayload = {
      sub: userId,
      email: userEmail,
      aud: 'tesouro',
      iss: clientId,
      exp: now + 300,  // 5 minutes
      iat: now,
    };

    const subjectToken =
      Buffer.from(JSON.stringify({ alg: 'none', typ: 'JWT' })).toString('base64url') + '.' +
      Buffer.from(JSON.stringify(subjectTokenPayload)).toString('base64url') + '.';

    // Step 2: Create encrypted token
    const payload = {
      aud: 'tesouro',
      client_id: clientId,
      client_secret: clientSecret,
      exp: now + 300,
      grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
      iat: now,
      iss: clientId,
      jti: crypto.randomUUID(),
      subject_token: subjectToken,
      subject_token_type: 'urn:ietf:params:oauth:token-type:access_token',
    };

    const token = await new EncryptJWT(payload)
      .setProtectedHeader({
        alg: 'A256KW',
        enc: 'A256GCM',
        kid: clientId,
        typ: 'JWT',
        cty: 'JWT',
      })
      .encrypt(secretKey);

    return token;
  }
Configuration: Tesouro provides TESOURO_CLIENT_ID, TESOURO_CLIENT_SECRET, and TESOURO_WIDGET_SECRET (exactly 32 bytes) during onboarding.

Additional resources

Learn more about JWTs and OAuth 2.0 Token Exchange (RFC 8693)