# Create Access Tokens

Source: https://developers.bitgo.com/docs/get-started-access-tokens

## Overview

Access tokens enable you to authenticate a session with BitGo and are either short lived (2 hours) or long lived (up to 10 years). Short-lived access tokens require a one-time password (OTP) for sensitive operations, such as withdrawals. Long-lived access tokens enable you to interact with BitGo APIs without an OTP, and are therefore better suited for integrations.

To create a long-lived access token, you must call the [Create Access Token](/reference/v2accesstokenadd) endpoint. However, calling this endpoint requires a short-lived access token that you must obtain from the [Login](/reference/userlogin) endpoint. This is the same underlying mechanism that enables you to log in to the BitGo web app and create an access token from the developer settings.

> 📘 **Note:** You can also create a long-lived access token directly from the BitGo web app. Go to your account settings and select **Developer Options** to create and manage tokens without using the API.

By default, BitGo requires you to include IP address or CIDR block restrictions for long-lived access tokens in the production environment. However, you can request an exception for tokens with read-only scopes (common for accounting, auditing, or reporting) by contacting [support@bitgo.com](mailto:support@bitgo.com).

> 📘 **Note:** CIDR blocks have a /24 to /32 prefix limit for security purposes.

### Best Practices

BitGo recommends the following to manage your access tokens:

* Use long-lived access tokens for your integration.
* Rotate your tokens frequently - don't let them last 10 years.
* Include a spending limit. If you omit a spending limit, you must [unlock](/reference/userunlock) the access token on a regular basis to permit sensitive operations, such as withdrawals.
* Practice the principle of least privilege (POLP) by assigning the fewest scopes necessary for an access token to perform its intended function.
* Manage your enterprise users in the BitGo web application, instead of programmatically, since user management can only be done with short-lived access token (with the `user_manage` scope).

### Passphrases

You can configure BitGo wallets to use passphrases when spending. For administrators who create access tokens, note the following:

* If you create the access token and the wallet, use the wallet passphrase to transact from the wallet (this may also be your BitGo-login passphrase).
* If you create the access token but someone else creates a wallet, use your BitGo-login passphrase to transact from the wallet.

## Prerequisites

Sign up for a BitGo account in the environment for which you're making a token. To learn more, see [Environments](/docs/get-started-environments).

## Cookbook

Need just the steps? Expand the cookbook below to get started:

<Cookbook slug="create-access-tokens" title="Create Access Tokens" />

## 1. Create Short-Lived Access Token

>Endpoint: [Login](/reference/v2userlogin)

```shell cURL
export EMAIL="<YOUR_EMAIL_ADDRESS>"
export OTP="<OTP>" # OTP is always 0000000 in test environment
export PASSWORD="<YOUR_LOGIN_PASSWORD>"

curl -X POST \
  https://app.bitgo-test.com/api/v2/user/login \
  -H 'Content-Type: application/json' \
  -d '{
  "email": "'"$EMAIL"'",
  "otp": "'"$OTP"'",
  "password": "'"$PASSWORD"'"
}'
```
```js JavaScript
bitgo.authenticate({ username: user, password: password, otp: '0000000' }).then(function (response) {
  var token = response.access_token;
  var user = response.user;
  // etc
});
```

#### Step Result

You receive a short-lived access token that you can use to create a long-lived access token.

```json JSON
{
  "token_type": "bearer",
  "access_token": "cb4125818839d3695e51ad74443e8362105f315e2495b3e905454430e948d556",
  "expires_in": 86400,
  "expires_at": 1763745105,
  "scope": [
    "user_manage",
    "openid",
    "openid_enterprises",
    "profile",
    "wallet_create",
    "wallet_freeze_all",
    "wallet_manage_all",
    "wallet_approve_all",
    "wallet_spend_all",
    "wallet_edit_all",
    "wallet_view_all",
    "settlement_network_read",
    "settlement_network_write",
    "trade_view",
    "trade_trade",
    "portfolio_view",
    "pending_approval_update",
    "metamask_institutional",
    "crypto_compare",
    "third_party_user_lookup",
    "enterprise_view_all",
    "enterprise_manage_all",
    "auditlogs_view_all",
    "ui_scope"
  ],
  "grant_type": "password",
  "user": {
    "id": "62ab90e06dfda30007974f0a52a12995",
    "username": "janedoe@email.com",
    "enterprises": [
      {
        "id": "61fab88a336c18000813831c85a3f2fe",
        "permissions": ["admin", "auditor"],
        "beneficialOwner": false,
        "acceptedInvite": true
      }
    ],
    "organizations": [],
    "name": { "full": "Jane Doe", "first": "Jane", "last": "Doe" },
    "email": { "email": "janedoe@email.com", "verified": true },
    "phone": { "phone": "", "verified": false },
    "country": "USA",
    "identity": {
      "kyc": {
        "documentsWaived": false,
        "unverifiedPaygoUser": false,
        "failureCount": 0,
        "fullyRequired": false,
        "required": true,
        "available": true,
        "hasVideoID": false,
        "passport": { "required": false, "state": "unverified" },
        "isScreeningRequired": true,
        "enterpriseVideoCallInfo": [],
        "data": {
          "state": "approved",
          "fields": {
            "country": "USA",
            "firstName": "Jane",
            "lastName": "Doe",
            "dob": "1997-05-05"
          }
        },
        "overallState": "approved",
        "documents": { "state": "unverified" },
        "residency": { "state": "unverified" },
        "ongoingScreening": { "state": "approved" }
      },
      "verified": false
    },
    "otpDevices": [
      {
        "id": "62ab917e4159d500079e5b836e41fba2",
        "createDate": "2022-06-16T20:24:30.000Z",
        "type": "totp",
        "label": "Google Authenticator",
        "verified": true,
        "lastValidatedDate": "2023-02-06T21:14:09.469Z",
        "scopes": []
      }
    ],
    "rateLimits": {},
    "disableReset2FA": false,
    "currency": { "currency": "USD", "bitcoinUnit": "BTC" },
    "timezone": "America/Los_Angeles",
    "isActive": true,
    "freeze": {},
    "ecdhKeychain": "xpub661MyMwAqRbcG9rxFyVx56soHRSzi6kCD1GPwd838qDJ1piucKe8JYfBS4VVLChNHZytXUkWf8sQb7jjXC1abjdS668rJEDjJrGQu1qVsCP",
    "referrer": { "source": null, "campaign": null },
    "forceResetPassword": false,
    "allowedCoins": [],
    "agreements": {
      "termsOfUse": 1,
      "termsOfUseAcceptanceDate": "2022-06-16T20:24:33.159Z",
      "patriotAct": 0
    },
    "lastLogin": "2025-10-22T18:41:07.117Z",
    "featureFlags": ["enableMPCv2"],
    "bitgoEmployee": false,
    "createTime": "2022-06-16T20:21:52.000Z",
    "state": "Texas",
    "sourceVerificationRequired": true,
    "sourceVerificationRequiredForReadOnlyAccess": true
  }
}
```

## 2. Create Long-Lived Access Token

Use the short-lived access token that you received in the prior step to authenticate the following call.

>Endpoint: [Create access token](/reference/v2accesstokenadd)

```shell cURL
export ACCESS_TOKEN="<YOUR_SHORT-LIVED_ACCESS_TOKEN>"
export OTP="<OTP>" # OTP is always 0000000 in test environment
export DURATION="<DURATION>"
export LABEL="<DESIRED_TOKEN_NAME>"
export IP_RESTRICT="<IP_ADDRESS_OR_CIDR_BLOCK>" # Required in production. CIDR blocks must have prefix lengths between /24 and /32 for IPv4, and between /64 and /128 for IPv6.
export ENTERPRISE="<YOUR_ENTERPRISE_ID>"
export COIN="<ASSET_ID>"
export TX_VALUE_LIMIT="<TX_VALUE_LIMIT>"

curl -X POST \
  https://app.bitgo-test.com/api/v2/user/accesstoken \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -d '{
  "otp": "'"$OTP"'",
  "scope": [
    "openid",
    "openid_enterprises",
    "profile",
    "wallet_create",
    "wallet_freeze_all",
    "wallet_manage_all",
    "wallet_approve_all",
    "wallet_spend_all",
    "wallet_edit_all",
    "wallet_view_all",
    "settlement_network_read",
    "settlement_network_write",
    "trade_view",
    "trade_trade",
    "portfolio_view",
    "pending_approval_update",
    "metamask_institutional",
    "crypto_compare",
    "third_party_user_lookup",
    "enterprise_view_all",
    "enterprise_manage_all",
    "auditlogs_view_all",
    "ui_scope"
  ],
  "duration": '$DURATION',
  "label": "'"$LABEL"'",
  "admin": false,
  "enterprise": "'"$ENTERPRISE"'",
  "spendingLimits": [
    {
      "coin": "'"$COIN"'",
      "txValueLimit": "'"$TX_VALUE_LIMIT"'",
      "maxLimit": false
    }
  ]
}'
```
```js JavaScript (long lived)
import { BitGoAPI } from '@bitgo/sdk-api';
const bitgo = new BitGoAPI({ env: 'test' });
const auth_res = await bitgo.authenticate({
  username: "user@example.com",
  password: process.env.PASS,
  otp: "0000000",
});
const access_token = await bitgo.addAccessToken({
  otp: "0000000",
  label: "Admin Access Token",
  scope: [
    "openid",
    "pending_approval_update",
    "profile",
    "settlement_network_read",
    "settlement_network_write",
    "trade_trade",
    "trade_view",
    "user_manage",
    "wallet_approve",
    "wallet_approve_all",
    "wallet_create",
    "wallet_edit",
    "wallet_edit_all",
    "wallet_edit_enterprise",
    "wallet_freeze",
    "wallet_freeze_all",
    "wallet_manage",
    "wallet_manage_all",
    "wallet_manage_enterprise",
    "wallet_spend",
    "wallet_spend_all",
    "wallet_spend_enterprise",
    "wallet_view",
    "wallet_view_all",
    "wallet_view_enterprise"
    ],
  spendingLimits: [
    {
      coin: "tbtc4",
      txValueLimit: "1000000000", // 10 TBTC4 (10 * 1e8)
    },
  ],
});
console.log(access_token);
```

#### Step Result

You receive an access token and an `id` for the token. Save this token for use in your integration. This token is unrecoverable. If you lose it, you must make another.

```json JSON
{
  "id": "693f4ee8b6f82977fda4793bf81dcfef",
  "client": "bitgo",
  "user": "62ab90e06dfda30007974f0a52a12995",
  "scope": [
    "openid",
    "openid_enterprises",
    "profile",
    "wallet_create",
    "wallet_freeze_all",
    "wallet_manage_all",
    "wallet_approve_all",
    "wallet_spend_all",
    "wallet_edit_all",
    "wallet_view_all",
    "settlement_network_read",
    "settlement_network_write",
    "trade_view",
    "trade_trade",
    "portfolio_view",
    "pending_approval_update",
    "metamask_institutional",
    "crypto_compare",
    "third_party_user_lookup",
    "enterprise_view_all",
    "enterprise_manage_all",
    "auditlogs_view_all",
    "ui_scope"
  ],
  "created": "2025-11-20T17:24:56.537Z",
  "expires": "2035-11-18T17:24:56.537Z",
  "ip": "75.237.71.150",
  "ipRestrict": [],
  "origin": "app.bitgo-test.com",
  "label": "My Bitcoin Token",
  "isExtensible": false,
  "isMobileAccessToken": false,
  "enterprise": "62c5ae8174ac860007aff138a2d74df7",
  "organizations": [],
  "unlock": {
    "time": "2025-11-20T17:24:56.543Z",
    "expires": "2035-11-18T17:24:56.537Z",
    "spendingLimits": {
      "tbtc4": { "txCount": 1, "txValue": 0, "txValueLimit": 100 }
    }
  },
  "oauth": { "oauthRequired": false },
  "token": "c1d856191baa8a0c16af7583aa6d4a4b3b222081361461b40041602ce0470ed6"
}
```

## See Also

* [API Reference: Create access token](/reference/v2accesstokenadd)
* [API Reference: List access tokens](/reference/v2accesstokenlist)
* [API Reference: Login](/reference/v2userlogin)
* [Concept: HMAC](/docs/hmac)
* [Environments](/docs/get-started-environments)
