curl --request POST \
--url https://api.sand.etherfuse.com/auth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
--data assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6Imt...const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: 'eyJhbGciOiJSUzI1NiIsImtpZCI6Imt...'
})
};
fetch('https://api.sand.etherfuse.com/auth/token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.sand.etherfuse.com/auth/token"
payload = {
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": "eyJhbGciOiJSUzI1NiIsImtpZCI6Imt..."
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
print(response.text){
"access_token": "<string>",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "<string>",
"scope": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>",
"error_uri": "<string>"
}Exchange a partner JWT
OAuth 2.0 token endpoint (RFC 6749 §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 instead.
Grant types
urn:ietf:params:oauth:grant-type:jwt-bearer(RFC 7523). Put the partner JWT inassertion.refresh_token(RFC 6749 §6). Put a priorrefresh_tokeninrefresh_token.
The JWT
Sign it with the key behind your registered JWKS (see 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 ascustomerIdin the Ramp API). Must name a person, never a business: a business org id is rejected withinvalid_grant, and asubcan’t be reused as a business org id (POST /ramp/organization returns 409). A non-UUIDsubstill 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/tokenin sandbox).scope: required. Names the flow the user may complete (see User Launch Flows); an unrecognized scope is rejected withinvalid_scope.jti/nonce: a fresh value, unique per token, for replay protection. You can send it asjti(the standard JWT ID) ornonce(the standard OIDC claim).exp,iat: required; keep tokens short-lived.email,name: required; populate the user’s profile.pictureis optional.
This endpoint is unauthenticated: the signed JWT (or refresh token) is the credential. Do not send an API key.
curl --request POST \
--url https://api.sand.etherfuse.com/auth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
--data assertion=eyJhbGciOiJSUzI1NiIsImtpZCI6Imt...const options = {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: 'eyJhbGciOiJSUzI1NiIsImtpZCI6Imt...'
})
};
fetch('https://api.sand.etherfuse.com/auth/token', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.sand.etherfuse.com/auth/token"
payload = {
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": "eyJhbGciOiJSUzI1NiIsImtpZCI6Imt..."
}
headers = {"Content-Type": "application/x-www-form-urlencoded"}
response = requests.post(url, data=payload, headers=headers)
print(response.text){
"access_token": "<string>",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "<string>",
"scope": "<string>"
}{
"error": "invalid_request",
"error_description": "<string>",
"error_uri": "<string>"
}Body
The OAuth 2.0 grant type.
urn:ietf:params:oauth:grant-type:jwt-bearer, refresh_token The partner-signed JWT. Required when grant_type is urn:ietf:params:oauth:grant-type:jwt-bearer.
A refresh token from a prior exchange. Required when grant_type is refresh_token.
Response
A bearer access token and refresh token
Bearer token for the Ramp API. Send it as Authorization: Bearer <access_token>.
"Bearer"
Access token lifetime, in seconds.
3600
Use with the refresh_token grant to obtain a fresh access token without re-signing a JWT.
The granted scope, echoed from the JWT's scope claim. Omitted for unrestricted (non-partner) sessions.