Advanced Trade API Authentication
This guide explains how to authenticate requests to the Advanced Trade REST API endpoints and WebSocket server channels. It assumes that you have already created API keys on the Coinbase Developer Platform.
Making Requests
CDP API keys are used to generate a JSON Web Token (JWT) for an API. Once you've generated a JWT, set it as a Authorization Bearer header to make an authenticated request.
# Example request to get account
curl -H "Authorization: Bearer $JWT" 'https://api.coinbase.com/api/v3/brokerage/accounts/f603f97c-37d7-4e58-b264-c27e9e393dd9'
Generating a JWT
Regardless of which code snippet you use, follow these steps:
- Replace
key name
andkey secret
with your key name and private key.key secret
is a multi-line key and newlines must be preserved to properly parse the key. Do this on one line with\n
escaped newlines, or with a multi-line string. - Replace the request method and path you want to test. If the URI has a UUID in the path, include that UUID here, e.g.,
/api/v3/brokerage/accounts/f603f97c-37d7-4e58-b264-c27e9e393dd9
. - Run the generation script that prints the command
export JWT=...
. - Run the generated command to save your JWT.
Your JWT expires after 2 minutes, after which all requests are unauthenticated.
You must generate a different JWT for each unique API request.
Code Samples
The easiest way to generate a JWT is to use the built-in functions in our Python SDK as described below.
Otherwise, use the code samples below to generate/export a JWT and make an authenticated request.
- Python SDK
- Python
- Go
- JavaScript
- PHP
- Java
-
Install the SDK.
pip3 install coinbase-advanced-py
-
In the console, run:
python main.py
(or whatever your file name is). -
Set the JWT to that output, or export the JWT to the environment with
eval $(python main.py)
. -
Make your request, example
curl -H "Authorization: Bearer $JWT" 'https://api.coinbase.com/api/v3/brokerage/accounts'
from coinbase import jwt_generator
api_key = "organizations/{org_id}/apiKeys/{key_id}"
api_secret = "-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n"
request_method = "GET"
request_path = "/api/v3/brokerage/accounts"
def main():
jwt_uri = jwt_generator.format_jwt_uri(request_method, request_path)
jwt_token = jwt_generator.build_rest_jwt(jwt_uri, api_key, api_secret)
print(f"export JWT={jwt_token}")
if __name__ == "__main__":
main()
-
Install dependencies
PyJWT
andcryptography
.pip install PyJWT
pip install cryptography -
In the console, run:
python main.py
(or whatever your file name is). -
Set the JWT to that output, or export the JWT to the environment with
eval $(python main.py)
. -
Make your request, example
curl -H "Authorization: Bearer $JWT" 'https://api.coinbase.com/api/v3/brokerage/accounts'
import jwt
from cryptography.hazmat.primitives import serialization
import time
import secrets
key_name = "organizations/{org_id}/apiKeys/{key_id}"
key_secret = "-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n"
request_method = "GET"
request_host = "api.coinbase.com"
request_path = "/api/v3/brokerage/accounts"
def build_jwt(uri):
private_key_bytes = key_secret.encode('utf-8')
private_key = serialization.load_pem_private_key(private_key_bytes, password=None)
jwt_payload = {
'sub': key_name,
'iss': "coinbase-cloud",
'nbf': int(time.time()),
'exp': int(time.time()) + 120,
'uri': uri,
}
jwt_token = jwt.encode(
jwt_payload,
private_key,
algorithm='ES256',
headers={'kid': key_name, 'nonce': secrets.token_hex()},
)
return jwt_token
def main():
uri = f"{request_method} {request_host}{request_path}"
jwt_token = build_jwt(uri)
print(f"export JWT={jwt_token}")
if __name__ == "__main__":
main()
- Create a new directory and generate a Go file called
main.go
. - Paste the Go snippet below into
main.go
. - Run
go mod init jwt-generator
andgo mod tidy
to generatego.mod
andgo.sum
to manage your dependencies. - In the console, run
go run main.go
. This outputs the command,export JWT=
. - Set your JWT with the generated output, or export the JWT to the environment with
eval $(go run main.go)
. - Make your request, for example
curl -H "Authorization: Bearer $JWT" 'https://api.coinbase.com/api/v3/brokerage/accounts'
package main
import (
"crypto/rand"
"crypto/x509"
"encoding/pem"
"fmt"
"math"
"math/big"
"time"
log "github.com/sirupsen/logrus"
"gopkg.in/square/go-jose.v2"
"gopkg.in/square/go-jose.v2/jwt"
)
const (
keyName = "organizations/{org_id}/apiKeys/{key_id}"
keySecret = "-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n"
requestMethod = "GET"
requestHost = "api.coinbase.com"
requestPath = "/api/v3/brokerage/accounts"
)
type APIKeyClaims struct {
*jwt.Claims
URI string `json:"uri"`
}
func buildJWT(uri string) (string, error) {
block, _ := pem.Decode([]byte(keySecret))
if block == nil {
return "", fmt.Errorf("jwt: Could not decode private key")
}
key, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
return "", fmt.Errorf("jwt: %w", err)
}
sig, err := jose.NewSigner(
jose.SigningKey{Algorithm: jose.ES256, Key: key},
(&jose.SignerOptions{NonceSource: nonceSource{}}).WithType("JWT").WithHeader("kid", keyName),
)
if err != nil {
return "", fmt.Errorf("jwt: %w", err)
}
cl := &APIKeyClaims{
Claims: &jwt.Claims{
Subject: keyName,
Issuer: "coinbase-cloud",
NotBefore: jwt.NewNumericDate(time.Now()),
Expiry: jwt.NewNumericDate(time.Now().Add(2 * time.Minute)),
},
URI: uri,
}
jwtString, err := jwt.Signed(sig).Claims(cl).CompactSerialize()
if err != nil {
return "", fmt.Errorf("jwt: %w", err)
}
return jwtString, nil
}
var max = big.NewInt(math.MaxInt64)
type nonceSource struct{}
func (n nonceSource) Nonce() (string, error) {
r, err := rand.Int(rand.Reader, max)
if err != nil {
return "", err
}
return r.String(), nil
}
func main() {
uri := fmt.Sprintf("%s %s%s", requestMethod, requestHost, requestPath)
jwt, err := buildJWT(uri)
if err != nil {
log.Errorf("error building jwt: %v", err)
}
fmt.Println("export JWT=" + jwt)
}
-
Install JSON Web Token:
npm install jsonwebtoken
-
In the console, run:
node main.js
(or whatever your file name is). -
Set the JWT to that output, or export the JWT to the environment with
eval $(node main.py)
. -
Make your request, example
curl -H "Authorization: Bearer $JWT" 'https://api.coinbase.com/api/v3/brokerage/accounts'
const { sign } = require('jsonwebtoken');
const crypto = require('crypto');
const key_name = 'organizations/{org_id}/apiKeys/{key_id}';
const key_secret = '-----BEGIN EC PRIVATE KEY-----\nYOUR PRIVATE KEY\n-----END EC PRIVATE KEY-----\n';
const request_method = 'GET';
const url = 'api.coinbase.com';
const request_path = '/api/v3/brokerage/accounts';
const algorithm = 'ES256';
const uri = request_method + ' ' + url + request_path;
const token = sign(
{
iss: 'coinbase-cloud',
nbf: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 120,
sub: key_name,
uri,
},
key_secret,
{
algorithm,
header: {
kid: key_name,
nonce: crypto.randomBytes(16).toString('hex'),
},
}
);
console.log('export JWT=' + token);
-
Add PHP dependencies with Composer (for JWT and environment variable management):
composer require firebase/php-jwt
composer require vlucas/phpdotenv -
Run
generate_jwt.php
(or a filename of your choice). -
Output the JWT to the command line and use a shell script to export it:
#!/bin/bash
export JWT=$(php generate_jwt.php) -
Make your request, for example:
curl -H "Authorization: Bearer $JWT" 'https://api.coinbase.com/api/v3/brokerage/accounts'
Code Snippet
<?php
require 'vendor/autoload.php';
use \Firebase\JWT\JWT;
use \Dotenv\Dotenv;
// Load environment variables
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
$privateKey = str_replace('\\n', "\n", $_ENV['PRIVATE_KEY']);
$name = $_ENV['NAME'];
$request_method = 'GET';
$url = 'api.coinbase.com';
$request_path = '/api/v3/brokerage/accounts';
$uri = request_method + ' ' + url + request_path;
// Header and payload
$header = [
'alg' => 'ES256',
'typ' => 'JWT',
'kid' => $name,
'nonce' => time()
];
$data = [
'iss' => 'coinbase-cloud',
'nbf' => time(),
'exp' => time() + 120, // Token expiration time
'sub' => $name,
'uri' => $uri,
];
// Generate JWT
$key = openssl_pkey_get_private($privateKey);
$jwt = JWT::encode($data, $key, 'ES256', $name);
echo $jwt;
?>
-
Add Java Dependencies to your project's Maven or Gradle configuration:
nimbus-jose-jwt, bouncycastle, and cdimascio-dotenv
-
Compile and run your Java application to generates a JWT, for example:
java -cp target/myapp.jar GenerateJWT
-
Capture and export the JWT output from your Java application to an environment variable:
export JWT=$(java -cp target/myapp.jar GenerateJWT)
-
Make an API Request, for example:
curl -H "Authorization: Bearer $JWT" 'https://api.coinbase.com/api/v3/brokerage/accounts'
Code Snippet
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jwt.*;
import java.security.interfaces.ECPrivateKey;
import java.util.Map;
import java.util.HashMap;
import java.time.Instant;
import java.util.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.KeyFactory;
import java.io.StringReader;
import java.security.PrivateKey;
import java.security.Security;
import io.github.cdimascio.dotenv.Dotenv;
public class Main {
public static void main(String[] args) throws Exception {
// Register BouncyCastle as a security providerx
Security.addProvider(new BouncyCastleProvider());
// Load environment variables
Dotenv dotenv = Dotenv.load();
String privateKeyPEM = dotenv.get("PRIVATE_KEY").replace("\\n", "\n");
String name = dotenv.get("NAME");
// create header object
Map<String, Object> header = new HashMap<>();
header.put("alg", "ES256");
header.put("typ", "JWT");
header.put("kid", name);
header.put("nonce", String.valueOf(Instant.now().getEpochSecond()));
// create uri string for current request
String requestMethod = "GET";
String url = "api.coinbase.com/api/v3/brokerage/accounts";
String uri = requestMethod + " " + url;
// create data object
Map<String, Object> data = new HashMap<>();
data.put("iss", "coinbase-cloud");
data.put("nbf", Instant.now().getEpochSecond());
data.put("exp", Instant.now().getEpochSecond() + 120);
data.put("sub", name);
data.put("uri", uri);
// Load private key
PEMParser pemParser = new PEMParser(new StringReader(privateKeyPEM));
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
Object object = pemParser.readObject();
PrivateKey privateKey;
if (object instanceof PrivateKey) {
privateKey = (PrivateKey) object;
} else if (object instanceof org.bouncycastle.openssl.PEMKeyPair) {
privateKey = converter.getPrivateKey(((org.bouncycastle.openssl.PEMKeyPair) object).getPrivateKeyInfo());
} else {
throw new Exception("Unexpected private key format");
}
pemParser.close();
// Convert to ECPrivateKey
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
ECPrivateKey ecPrivateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
// create JWT
JWTClaimsSet.Builder claimsSetBuilder = new JWTClaimsSet.Builder();
for (Map.Entry<String, Object> entry : data.entrySet()) {
claimsSetBuilder.claim(entry.getKey(), entry.getValue());
}
JWTClaimsSet claimsSet = claimsSetBuilder.build();
JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.ES256).customParams(header).build();
SignedJWT signedJWT = new SignedJWT(jwsHeader, claimsSet);
JWSSigner signer = new ECDSASigner(ecPrivateKey);
signedJWT.sign(signer);
String sJWT = signedJWT.serialize();
System.out.println(sJWT);
}
}