Skip to main content

Authentication

All IDCloud APIs (Web & SDK and API contracts) use OAuth2 with JWT Bearer Grant Type (RFC 7523). You generate a short-lived JWT assertion on your back-end, exchange it for a Bearer token, and use that token in every subsequent call.

Never do this on the client side

The JWT assertion must be generated on your back-end only. Never expose your private key in front-end code, mobile apps, repositories, or logs.

Obtaining credentials

Before you can generate tokens, you need a service account provisioned by Unico. Contact Unico support and provide:

  • Service account name (max 12 characters)
  • Responsible person's name, email and phone (Brazil, US or Mexico numbers only)

You will receive:

  • Unique account name
  • Tenant ID
  • Base JWT payload
  • Private key file (.pem format)
One account per environment

Keep separate service accounts for UAT and Production.

Building the JWT assertion

The assertion is a JWT in compact JWS format: {Base64url(Header)}.{Base64url(Payload)}.{Base64url(Signature)}.

Header
{
"alg": "RS256",
"typ": "JWT"
}
Payload
ClaimValueNotes
iss<account_name>@<tenant_id>.iam.acesso.ioProvided with your credentials
audhttps://identityhomolog.acesso.io (UAT) or https://identity.acesso.io (Production)Must match the token endpoint host
scope*Grants all permissions
iatUnix timestamp (seconds)Time the JWT was issued
expiat + max 3600Cannot exceed 1 hour from iat
{
"aud": "https://identity.acesso.io",
"scope": "*",
"iat": 1738086000,
"exp": 1738089600
}
Signature

Sign the header + payload using RS256 (RSA + SHA-256) with the .pem private key provided by Unico.

Do not add extra claims

Any field not listed above (e.g. sub, jti, nbf) will cause a 1.2.22 error. Use only the claims shown.

Requesting the token

The token endpoint is the same for both contracts:

EnvironmentEndpoint
ProductionPOST https://identity.acesso.io/oauth2/token
UATPOST https://identityhomolog.acesso.io/oauth2/token
Request
ParameterValue
Content-Typeapplication/x-www-form-urlencoded
grant_typeurn:ietf:params:oauth:grant-type:jwt-bearer
assertionYour signed JWT
curl -X POST https://identity.acesso.io/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
-d "assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
Response
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
FieldTypeDescription
access_tokenstringJWT access token. Use in Authorization: Bearer <token> on all API calls.
expires_inintegerExpiration time in seconds. Example: 3600.
token_typestringAlways Bearer.

Using the token

Add the token to the Authorization header of every API request. The header is identical for both contracts — what differs is the host and path of the API you're calling:

ContractProduction hostUAT host
Web & SDKhttps://api.idcloud.unico.apphttps://api.idcloud.uat.unico.app
APIhttps://api.id.unico.apphttps://api.id.uat.unico.app

Web & SDKAuthorization is the only auth header required:

curl -X POST https://api.idcloud.unico.app/client/v1/process \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'

APIAuthorization is used alongside the APIKEY header:

curl -X POST https://api.id.unico.app/processes/v1 \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "APIKEY: $API_KEY" \
-H "Content-Type: application/json" \
-d '{ ... }'

Token renewal

Tokens expire after 3600 seconds. Implement proactive renewal in your back-end:

  • Track expires_in from the token response and store the expiry timestamp.
  • Request a new token when 10 minutes or less remain before expiration.
  • Never wait for a 401 in production to trigger a renewal.

API reference

The full OpenAPI specification for the token endpoint is available in authentication.yaml.

MethodPathDescription
POST/oauth2/tokenExchange a signed JWT assertion for a Bearer access token

Error codes

CodeDescriptionAction
1.0.1The ID provided in the formation of iss is incorrectVerify the iss field matches the tenant ID provided when the private key was generated
1.0.14Application is not activeCheck with the project manager if the application being used is active
1.1.1The scope parameter was not providedAdd "scope": "*" to your JWT payload
1.2.4JWT assertion invalidThe JWT assertion is no longer valid. Two causes: (a) the current time is past exp (JWT truly expired — generate a fresh assertion for each token request); or (b) exp exceeds iat + 3600 (lifetime too long — cap exp at iat + 3600).
1.2.5JWT validation failedThe JWT cannot be validated. Verify the parameters and ensure it was signed with RS256 and the correct private key
1.2.6Private key is no longer validThe private key used to sign the JWT is no longer acceptable. Request new credentials for the account
1.2.7JWT already usedThe JWT is no longer acceptable as it has already been used. Generate a new assertion for each token request
1.2.11Account is not activeThe account used is not active
1.2.14Account lacks necessary permissionsThe account used does not have the necessary permissions
1.2.18Account temporarily lockedThe account has been temporarily locked due to exceeding the number of invalid authentication attempts
1.2.19Unauthorized user impersonationThe JWT contains a sub claim pointing to an account that is not authorized for impersonation. Remove the sub claim from the payload.
1.2.20JWT decoding failedFailed to decode the JWT. Verify the token format and that it was signed with RS256.
1.2.21Wrong private key / Authentication failedThe JWT signature could not be verified against any known key for this account. Check that you are using the correct .pem private key for this service account and environment.
1.2.22Disallowed fields in payloadThe JWT contains extra payload fields that are not allowed. Remove any claims not listed in this guide (e.g. sub, jti, nbf). Note: if you included a sub claim and received 1.2.19 instead, that error takes precedence.
1.3.1IP access restrictionYour IP is not in the allowlist for this account
1.3.2Time-based access restrictionRequest is outside the permitted time window for this account

What's next