> ## Documentation Index
> Fetch the complete documentation index at: https://developers.authlete.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Two-Step API Calls

> How actions such as INTERACTION are completed with a second API call — /auth/authorization/issue or /auth/authorization/fail — linked by a ticket.

Some actions cannot be completed in a single API call. When the [/auth/authorization](/api-reference/authorization-endpoint/process-authorization-request) API returns `action=INTERACTION`, your authorization server must authenticate the user and obtain consent before the authorization request can be answered — and that answer is produced by a **second** Authlete API call.

## Two Types of Authorization Endpoint APIs

The [Authorization Endpoint APIs](/api-reference/authorization-endpoint) consist of two types:

1. An API that interprets the authorization request and provides the information needed for the next step, such as end-user authentication:
   * [/auth/authorization](/api-reference/authorization-endpoint/process-authorization-request)
2. APIs that issue tokens or codes, or return errors:
   * [/auth/authorization/issue](/api-reference/authorization-endpoint/issue-authorization-response), [/auth/authorization/fail](/api-reference/authorization-endpoint/fail-authorization-request)

The typical flow for `action=INTERACTION` looks like this:

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant UA as Web Browser
    participant AS as Authorization Server
    participant API as Authlete Core API
    UA ->> AS: Authorization request
    AS ->> API: POST /auth/authorization
    API -->> AS: action=INTERACTION, ticket
    AS ->> UA: Authentication and consent page
    UA ->> AS: User authenticates and consents
    AS ->> API: POST /auth/authorization/issue (ticket)
    API -->> AS: action=LOCATION, responseContent
    AS ->> UA: 302 Found (authorization code)
```

## Flow Steps

### The Authorization Request and the First Call

An OAuth 2.0 / OpenID Connect flow begins when a client redirects the end-user's browser to your authorization server's authorization endpoint. The request sent at that point — a query string containing `response_type`, `client_id`, `redirect_uri`, `scope`, and so on — is the "Authorization request" in the diagram above.

Your server passes the request through to [/auth/authorization](/api-reference/authorization-endpoint/process-authorization-request) unmodified (see [Request and Response](/get-started/concepts/request-and-response) for details). When the authorization request requires interaction with the end-user, Authlete returns a response like this:

```json theme={null}
{
  "action": "INTERACTION",
  "ticket": "cElOaH9j4mS6AiIGR9oLqHlDn9jpvcNjqSgyRqfcmAE",
  "client": { "..." },
  "service": { "..." }
}
```

* `action=INTERACTION` means the end-user must be involved — authenticated and asked for consent — before the authorization request can be answered.
* `ticket` carries the processing over to the second call (see [The Ticket](#the-ticket) below for its properties).
* The response also carries client and service information, along with the scopes and claims the client requested. Your server uses these to build the consent screen.

### Presenting the Authentication and Consent Screen

**Rendering the authentication/consent screen, authenticating the user, and obtaining consent are all your authorization server's responsibility** — Authlete does not render these screens. Your server uses the information from the first response to present the consent screen. Meanwhile, hold the `ticket` on the server side (for example, in the session) until the second call.

### The Second Call and Building the Authorization Response

Once the user has authenticated and consented, your server makes the second call to [/auth/authorization/issue](/api-reference/authorization-endpoint/issue-authorization-response). This request includes the `ticket` received in the first call and the `subject` — the identifier of the authenticated end-user.

```bash theme={null}
curl -s -X POST https://us.authlete.com/api/{Service ID}/auth/authorization/issue \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "ticket": "{the ticket from the first response}", "subject": "{the authenticated end-user identifier}" }'
```

If you use a different region, replace `us.authlete.com` with your cluster host (e.g. `eu.authlete.com`, `jp.authlete.com`). See [Authentication](/get-started/concepts/authentication) for how to obtain a Service Access Token.

When issuing an OpenID Connect ID token, you can also pass `authTime` (the time the user was authenticated), `acr` (the authentication context class), the requested claim values, and more. See the [/auth/authorization/issue](/api-reference/authorization-endpoint/issue-authorization-response) API reference for the full list of parameters.

On success, the response `action` is typically `LOCATION`, and `responseContent` holds the redirect URL containing the authorization code. Your server uses this value to return `302 Found` to the browser, delivering the authorization response to the client. Handle the `action` of this second response exactly as described in [Action Handling](/get-started/concepts/action-handling).

If the user cancels or authentication fails, call [/auth/authorization/fail](/api-reference/authorization-endpoint/fail-authorization-request) — with the same `ticket` — instead of [/auth/authorization/issue](/api-reference/authorization-endpoint/issue-authorization-response), and Authlete builds the appropriate error response for the client.

## The Ticket

As shown above, a ticket is issued in the response of the first call and consumed by the second call to complete the processing — it is a single-use value. Its properties:

* A ticket expires in 24 hours. Expired tickets are deleted from Authlete's database.
* A ticket can be used only once. It is removed right after [/auth/authorization/issue](/api-reference/authorization-endpoint/issue-authorization-response) or [/auth/authorization/fail](/api-reference/authorization-endpoint/fail-authorization-request) successfully processes a request including it.
* Using a ticket that has already been used or expired results in an error like this:

```
[A041202] There is no entity having the ticket specified
in the /api/auth/authorization/issue request (ticket = {Ticket}).
```

<Warning>
  Tickets are designed to be used only between your authorization server and the Authlete server. Do not expose them to user agents such as web browsers — for example, never use a ticket to manage browser sessions.
</Warning>

## The Same Model in Other APIs

The userinfo endpoint is a good example of the same model. The [/auth/userinfo](/api-reference/userinfo-endpoint/process-userinfo-request) API validates the access token presented by the client and returns an `action`. When the action is `OK`, your server gathers the end-user's claim values and calls [/auth/userinfo/issue](/api-reference/userinfo-endpoint/issue-userinfo-response) to build the userinfo response — Authlete formats it as plain JSON or as a signed/encrypted JWT according to the client's configuration. The userinfo endpoint does not use a ticket; here the access token itself carries the context between the two calls.

<Note>
  The token endpoint also has two-step variants: when your service supports the Resource Owner Password Credentials grant, the [/auth/token](/api-reference/token-endpoint/process-token-request) API returns `action=PASSWORD`, and your server validates the end-user's credentials before calling [/auth/token/issue](/api-reference/token-endpoint/issue-token-response) or [/auth/token/fail](/api-reference/token-endpoint/fail-token-request). The same pattern applies to `TOKEN_EXCHANGE` ([RFC 8693](https://www.rfc-editor.org/rfc/rfc8693)) and `JWT_BEARER` ([RFC 7523](https://www.rfc-editor.org/rfc/rfc7523)), where your server validates the subject token or assertion.
</Note>

Once you understand the `action`-based model and the two-step pattern, every Core API follows naturally from its API reference.
