Skip to content

Exchange a code, or refresh a token

POST
/oauth/token
curl --request POST \
--url https://api.nsin.ir/oauth/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data client_id=example \
--data client_secret=example \
--data code=example \
--data redirect_uri=example \
--data code_verifier=example \
--data refresh_token=example \
--data scope=example

Accepts application/x-www-form-urlencoded (the OAuth default) and JSON. A confidential client authenticates with client_secret_post or HTTP Basic; a public client sends no secret and is protected by PKCE alone.

grant_type=authorization_code — send code, redirect_uri, client_id and code_verifier. The code is single-use and lives five minutes. A code that never existed, has expired or has already been redeemed all answer the same invalid_grant.

grant_type=refresh_token — send refresh_token and client_id. Refresh tokens rotate: the response carries a new one and the presented token is burnt. Presenting a burnt token is treated as a leak and revokes every token of that login. scope may be sent to narrow the new token; it can never widen.

A refresh_token is only issued when the offline_access scope was granted. Rate limited to 60 requests per minute per IP and 600 per minute per client_id.

The union of both grant types. Send it form-encoded or as JSON.

object
grant_type
required
string
Allowed values: authorization_code refresh_token
client_id
required
string
client_secret

Confidential clients only, and only when not using HTTP Basic. A public client never sends one.

string
code

authorization_code only — the value from the redirect.

string
redirect_uri

authorization_code only — must equal the one the code was issued for.

string
code_verifier

authorization_code only. The PKCE verifier, 43–128 characters from [A-Za-z0-9._~-], whose SHA-256 produced the code_challenge.

string
refresh_token

refresh_token only.

string
scope

refresh_token only, and optional: narrows the new token. It can never widen — asking for more than was granted is invalid_scope.

string

A fresh token set.

Media type application/json
object
access_token

RS256 JWT. Verify it against the JWKS.

string
token_type
string
Allowed values: Bearer
expires_in

Access token lifetime in seconds.

integer
refresh_token

Present only when offline_access was granted.

string
id_token

RS256 JWT carrying the identity claims the scopes allow.

string
scope

The scopes actually granted

string
Example
{
"token_type": "Bearer"
}

invalid_request, unsupported_grant_type, invalid_grant (unknown, expired, already-used or mismatched code or refresh token — deliberately indistinguishable), invalid_scope, or unauthorized_client for a client that has been switched off.

Media type application/json

The RFC 6749 error shape, used by the NSIN SSO endpoints only. It is deliberately different from Error: OAuth clients match on the machine error code, and only show error_description to a developer.

object
error
required

The machine-readable code.

string
error_description

A human-readable explanation. Never match on this.

string
Example
{
"error": "invalid_grant",
"error_description": "authorization code is invalid or expired"
}

invalid_client — the client id is unknown or the secret is wrong. Carries WWW-Authenticate: Basic when Basic auth was attempted.

Media type application/json

The RFC 6749 error shape, used by the NSIN SSO endpoints only. It is deliberately different from Error: OAuth clients match on the machine error code, and only show error_description to a developer.

object
error
required

The machine-readable code.

string
error_description

A human-readable explanation. Never match on this.

string
Example
{
"error": "invalid_grant",
"error_description": "authorization code is invalid or expired"
}

Too many token requests.

Media type application/json

The single error shape used by every endpoint.

object
error
required

Human-readable description of what went wrong.

string
Examples
Example slowDown
{
"error": "slow_down"
}