Create 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 endpoint. However, calling this endpoint requires a short-lived access token that you must obtain from the Login 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.
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 [email protected].
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 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_managescope).
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.
1. Create Short-Lived Access Token
Endpoint: Login
export EMAIL="<YOUR_EMAIL_ADDRESS>"
export OTP="<OTP>" # OTP is always 000000 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"'"
}'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.
{
"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": "[email protected]",
"enterprises": [
{
"id": "61fab88a336c18000813831c85a3f2fe",
"permissions": ["admin", "auditor"],
"beneficialOwner": false,
"acceptedInvite": true
},
{
"id": "62c5ae8174ac860007aff138a2d74df7",
"permissions": ["admin", "auditor"],
"beneficialOwner": false,
"acceptedInvite": true
},
{
"id": "640971cfba5a34e391cd52daaaffd4c6",
"permissions": ["admin", "auditor"],
"beneficialOwner": false,
"acceptedInvite": true
},
{
"id": "5ef51a6c7c74daa7004d4e23c62022b2",
"permissions": ["admin", "auditor"],
"beneficialOwner": false,
"acceptedInvite": true
}
],
"organizations": [],
"name": { "full": "Jane Doe", "first": "Jane", "last": "Doe" },
"email": { "email": "[email protected]", "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
export ACCESS_TOKEN="<YOUR_SHORT-LIVED_ACCESS_TOKEN>"
export OTP="<OTP>" # OTP is always 000000 in test environment
export DURATION="<DURATION>"
export LABEL="<DESIRED_TOKEN_NAME>"
export IP_RESTRICT="<IP_ADDRESS_OR_CIDR_BLOCK>" # Required in production
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
}
]
}'import { BitGoAPI } from '@bitgo/sdk-api';
const bitgo = new BitGoAPI({ env: 'test' });
const auth_res = await bitgo.authenticate({
username: "[email protected]",
password: process.env.PASS,
otp: "000000",
});
const access_token = await bitgo.addAccessToken({
otp: "000000",
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.
{
"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
Updated 2 days ago