Skip to main content

OAuth Token Authentication

To make authorized API calls to Nopan, clients must first obtain an OAuth 2.0 access token.
This token is issued using the client_credentials grant and requires mutual TLS (mTLS) with your client certificate.

The resulting access token must be included in all subsequent API requests using the Authorization header.

mTLS Required

All token requests must use mutual TLS (mTLS) with your registered client certificate.
Without a valid certificate, the token endpoint will reject your request.


Requesting an OAuth Token

Use the following examples to request an OAuth 2.0 access token for authenticating with Nopan APIs:

cURL - POST /auth/token
curl --cert client-cert.pem --key client-key.pem \
-X POST https://api.nopan.com/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id={{your_organization_id}}" \
--data-urlencode "scope=payments:process"

Scopes

We currently support next scopes:

Scope
Purpose
payments:read
Read-only access to payment objects, status queries. Applied by default.
payments:process
Allows initiating, capturing, refunding, and canceling payments. Must be explicitly requested.
data:reports
Allows obtaining reports over API. Must be explicitly requested.

To request non-default processing scope, include it in the token request:

cURL - POST /auth/token
curl --cert client-cert.pem --key client-key.pem \
-X POST https://api.nopan.com/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id={{your_organization_id}}" \
--data-urlencode "scope=payments:process"

Inspecting Your OAuth Access Token

Access tokens are issued as JWTs. You usually don’t need to decode the JWT because expires_in within the /auth/token response tells you token lifetime. Your response will look like this:

{
"access_token": "...",
"expires_in": 7200,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": "payments:process"
}
  • expires_in : lifetime in seconds (e.g., 7200 = 2 hours).
  • refresh_expires_in : always 0. There are no refresh tokens; always request a new access token when the old one expires.
info

Same token could be used for multiple requests within the allowed scope.

Best Practice

Renew tokens automatically a few minutes before expires_in elapses (e.g., 5 minutes before expiration).

Check the OpenAPI spec for /auth/token spec for the response format.

Using the Token

After you obtain the token, include it in your API calls:

cURL - POST /payments/initiate
curl -X POST https://api.nopan.com/payments/initiate \
-H "Authorization: Bearer <access-token>" \
-H "Idempotency-Key: 63c2e3f0-12aa-41bb-ae62-f3d91fdbb762" \
-H "Signature: nopan_sig=<signature>" \
-H "Signature-Input: nopan_sig=("@status");keyid="your-key-id";created=1766678793 \
-H "Content-Type: application/json" \
-d '{
"clientTransactionId": "order123",
"transactionType": "ONE_TIME",
"paymentDetails": {
"amount": 100,
"currency": "PLN",
"country": "PL",
"description": "Product ID 1234 purchase"
},
"providerDetails": {
"providerId": "BLIK"
},
"payerDetails": {
"payerId": "payerUUID",
"oneTimeCode": "123456"
}
}'
info

For signing requests, see HTTP Signatures.

Common errors

Cause
HTTP Status
Nopan Error
Recommended Action
Client certificate not provided (mTLS)
400 Bad Request
4980
Your system must present a valid TLS certificate when connecting.
Token is expired or invalid
401 Unauthorized
4061
The provided token was revoked or expired. Refresh or re-authenticate.
Unauthorized – no valid credentials
401 Unauthorized
4970
Access token is missing or invalid.
Authenticated, but access is forbidden
403 Forbidden
4971
You’re authenticated but not authorized to access this resource (e.g., wrong scope or cert trust failure).

Debugging Access Token

Decode the token only when debugging auth issues or validating configuration. There are a few ways to inspect your JWT token.

Using the Command Line

Decode the token payload locally for safe inspection:

TOKEN=eyJhbGciOi...<snip>...XYZ

# Extract payload and decode
echo "$TOKEN" |
cut -d '.' -f2 |
base64 -d | jq

Using the JWT.io Debugger

Paste your token into https://jwt.io to decode and inspect its contents.

warning

Avoid using real production tokens in online tools.

Example output:

{
"exp": 1735750000,
"iat": 1735745000,
"scope": "payments:process",
"client_id": "your-organization-id",
...
}