Approve an authorization request
Auth: panel session — see API keys.
The server side of the panel's /oauth/authorize page. It is called by
the NSIN panel with the signed-in user's session, never by a relying
party: your application's part of this step is the browser redirect to
{panel}/oauth/authorize?…, and the redirect back that follows.
Documented here because it defines the parameters your redirect must
carry. state is required. PKCE is mandatory for every client:
code_challenge_method must be S256 and code_challenge must be
BASE64URL(SHA256(code_verifier)) with a verifier of 43–128 unreserved
characters.
A first-party client asking only for identity scopes is approved
silently. Everything else needs a stored grant — a third-party client
for any scope, and ANY client, first-party included, that asks for
nsin:full — because the grant carries the user's domain
selection. The first request answers consent_required with the
client's name, the human descriptions of the scopes and, when
nsin:full is requested, a domain_access block (the current
selection and every domain the user could pick). The panel shows the
consent card with a domain picker and repeats the request with
consent: true and domains ("all", or a list of domain ids the
user has a role on). Every credential obtained through the grant — the
access token, and any nsin_ key the app mints with it — is bound to
the client and limited, live, to that selection; GET /whoami reports
it as domain_access, and revoking the app in Connected apps leaves
those credentials no domain at all.
prompt=none is the silent sign-in probe: a covering grant answers
with the redirect as usual, anything else answers consent_required
and nothing is written (the panel turns it into
error=consent_required on the redirect_uri). prompt=consent always
shows the card, prefilled from the existing grant, so a connected app
can offer "change domain access".
Request body
Content type: application/json · required
- client_idstringrequired
- redirect_uristringrequired
Must match one of the client's registered URIs exactly.
- response_typestringrequiredOne of:
"code" - scopestringrequired
Space-separated. Must include
openid. - statestringrequired
Opaque value echoed back on the redirect. Required.
- code_challengestringrequired
- code_challenge_methodstringrequiredOne of:
"S256" - noncestring
Echoed in the ID token.
- consentboolean
Set by the panel when the user approves the consent card.
- promptstring
nonenever interacts and never writes a grant;consentalways shows the card. Anything else is ignored.One of:"none""consent" - domainsstring | array of integer
The domain selection. Required with
consent: truewhennsin:fullis requested, ignored otherwise:"all", or a non-empty list of domain ids the user owns or is a member of. An id outside that set answers400 invalid_requestwitherror_description"domain not accessible".Fields
- Option 1string
- Option 2array of integer
Responses
200Either the URL to send the browser to, or a request for consent.
Content type: application/json
- Option 1object
Fields
- redirect_tostring
The registered redirect_uri with
code,stateandissappended.
- Option 2object
Fields
- consent_requiredbooleanOne of:
true - clientobject
Fields
- namestring
- descriptionstring
- first_partyboolean
- scopesarray of object
Item fields
- idstring
- descriptionstring
- domain_accessobject
Present only when
nsin:fullis requested.Fields
- currentstring | array of integer
The existing grant's selection, to prefill the picker —
"all"when there is none.Fields
- Option 1string
- Option 2array of integer
- domainsarray of object
Every domain the user has a role on, sorted by name, at most 1000.
Item fields
- idinteger
- namestring
- rolestringOne of:
"owner""admin""editor""viewer"
{
"redirect_to": "https://app.example/auth/callback?code=nac_…&state=xyz&iss=https%3A%2F%2Fapi.nsin.ir"
}400invalid_client, invalid_redirect_uri, unsupported_response_type,
invalid_request (missing or malformed PKCE / state, or a missing
or inaccessible domains selection) or invalid_scope.
Content type: application/json
- errorstringrequired
The machine-readable code.
- error_descriptionstring
A human-readable explanation. Never match on this.
{
"error": "invalid_grant",
"error_description": "authorization code is invalid or expired"
}401No panel session, or a legacy session token with no session id.
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
{
"error": "read-only API key"
}403The account is not active.
Content type: application/json
- errorstringrequired
Human-readable description of what went wrong.
{
"error": "read-only API key"
}Example request
curl -X POST "https://api.nsin.ir/oauth/authorize" \
-H "Authorization: Bearer $NSIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"client_id": "string",
"redirect_uri": "string",
"response_type": "code",
"scope": "openid profile email offline_access",
"state": "string",
"code_challenge": "string",
"code_challenge_method": "S256",
"nonce": "string",
"consent": true,
"prompt": "none",
"domains": "all"
}'