Skip to main content

Authentication

Most operations on the Vasco API require an authenticated user. Authentication uses OAuth 2.0: you exchange a user's credentials for a short-lived access token at the /oauth/token endpoint, then send that token as a Bearer credential on every request to the authenticated GraphQL endpoint.

Prerequisites

Getting an OAuth2 client​

The OAuth2 flow requires client credentials — a client_id and, for confidential clients, a client_secret — that identify your integration. These are issued by Vasco: they are not self-service.

To obtain them, contact Vasco and provide:

  • The environment(s) you need access to (production, preproduction).
  • A short description of your integration.
  • The grant types you intend to use (typically password and refresh_token).

Vasco will provision an OAuth2 client and return your client_id and client_secret.

Keep your secret safe

The client_secret is a confidential credential. Store it in a secret manager, never commit it to source control, and never expose it in a browser or mobile client. If it leaks, ask Vasco to rotate it.

Obtaining a token​

Send a POST request to /oauth/token with the password grant. Include your client credentials together with the user's credentials:

curl -X POST https://api.<client>.vasco.fund/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=<YOUR_CLIENT_ID>" \
-d "client_secret=<YOUR_CLIENT_SECRET>" \
-d "username=user@example.com" \
-d "password=<password>"

A successful response is a standard OAuth2 token payload:

{
"token_type": "Bearer",
"expires_in": 900,
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpXXXXXX.YYYYYY",
"refresh_token": "def502004a...ZZZZZZ"
}
FieldDescription
access_tokenThe JWT to send on authenticated requests. Valid for expires_in seconds.
expires_inAccess token lifetime in seconds (15 minutes by default).
refresh_tokenLong-lived token used to obtain a new access token without re-sending credentials.
token_typeAlways Bearer.

Two-factor authentication​

If the user has two-factor authentication (TOTP) enabled, you must include their current one-time code as otp_code:

curl -X POST https://api.<client>.vasco.fund/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=<YOUR_CLIENT_ID>" \
-d "client_secret=<YOUR_CLIENT_SECRET>" \
-d "username=user@example.com" \
-d "password=<password>" \
-d "otp_code=123456"

When 2FA is required and otp_code is missing or invalid, the endpoint returns 400 with error: invalid_grant.

Using the token​

Pass the access token as a Bearer credential on every request to the authenticated GraphQL endpoint:

POST /graphql/ HTTP/1.1
Host: api.<client>.vasco.fund
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpXXXXXX.YYYYYY
Content-Type: application/json

{ "query": "query { GetCurrentUser { id email } }" }

Refreshing a token​

Access tokens are short-lived. Rather than re-sending the user's credentials, exchange the refresh_token for a fresh access token using the refresh_token grant:

curl -X POST https://api.<client>.vasco.fund/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "client_id=<YOUR_CLIENT_ID>" \
-d "client_secret=<YOUR_CLIENT_SECRET>" \
-d "refresh_token=<YOUR_REFRESH_TOKEN>"

The response has the same shape as the initial token response, with a new access_token and a new refresh_token. Each refresh rotates the refresh token: the one you sent is invalidated, so always store the refresh_token returned by the latest response and use it for the next refresh.

Refresh tokens are valid for 6 hours and cannot be renewed indefinitely. The absolute lifetime of 12 hours is counted from the start of the refresh chain — the original password grant — not from the most recent refresh. Once that limit is reached, the user must authenticate again with the password grant.

Revoking a token​

To log a user out, revoke their refresh token at /oauth/revoke (RFC 7009). Revoking a refresh token also invalidates the access token it is linked to:

curl -X POST https://api.<client>.vasco.fund/oauth/revoke \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=<YOUR_CLIENT_ID>" \
-d "client_secret=<YOUR_CLIENT_SECRET>" \
-d "token=<REFRESH_TOKEN>" \
-d "token_type_hint=refresh_token"

Set token_type_hint=access_token to revoke an access token directly. The endpoint returns 200 even for an unknown or malformed token — revocation is idempotent. The one exception is a missing or empty token parameter, which returns 400 with error: invalid_request.

Error responses​

Errors follow the OAuth2 convention — a JSON body with an error code and an optional error_description:

{
"error": "invalid_grant",
"error_description": "Invalid credentials."
}
HTTP statuserrorMeaning
400invalid_grantWrong username/password, or a missing/invalid otp_code.
400invalid_grantToo many one-time-code attempts (max 5 per 5 minutes) — returned with the same code as an incorrect otp_code.
400invalid_grantA refresh_token that is expired, already used (rotated away), or has reached the 12-hour absolute lifetime.
400invalid_requestA missing or empty token parameter on /oauth/revoke.
401invalid_clientUnknown client_id or wrong client_secret.
429invalid_grantToo many failed attempts — the login endpoint is rate-limited per IP and per (username, IP) pair. Wait ~1 minute and retry.

When an authenticated GraphQL request is rejected because the access token is missing, malformed, or expired, obtain a new token via the refresh flow (or the password grant if the refresh token has also expired).

Forgotten password​

A user who has lost their password can trigger the standard reset flow without being authenticated:

  1. RequestPasswordReset — sends a reset email to the user.
  2. ResetPassword — consumes the token from the email and sets a new password.

Operations that do not require a token​

Sign-up and password-reset operations are exposed on the public GraphQL endpoint and can be called anonymously. Browse the Public API section of the API Reference for the full list.

Deprecated: password login (/auth/login)​

Deprecated

The legacy POST /auth/login endpoint — which exchanges a username and password directly for a JWT — is deprecated and will be removed in a future release. It does not support OAuth2 client credentials, refresh tokens, or token revocation. Migrate all integrations to the OAuth2 flow above.

For reference, the deprecated flow sent credentials to /auth/login:

# Deprecated — do not use for new integrations.
curl -X POST https://api.<client>.vasco.fund/auth/login \
-H "Content-Type: application/json" \
-d '{
"username": "user@example.com",
"password": "<password>"
}'

and returned the JWT directly:

{ "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpXXXXXX.YYYYYY" }

Migrating from /auth/login​

Legacy (/auth/login)OAuth2 (/oauth/token)
POST /auth/login, JSON bodyPOST /oauth/token, application/x-www-form-urlencoded body
username + passwordgrant_type=password + client_id + client_secret + username + password
No client credentialsRequires an OAuth2 client — request one from Vasco
Response: { "token": "..." }Response: { "access_token": "...", "refresh_token": "...", "expires_in": 900, "token_type": "Bearer" }
Re-send credentials when the JWT expiresUse the refresh_token grant to renew

The way you attach the token to GraphQL requests is unchanged: pass it in the Authorization: Bearer header exactly as before. What changes is the token endpoint's response body — { "token": "..." } becomes { "access_token": "...", "refresh_token": "...", ... } — so read the token from access_token instead of token.