# `AttestoPhoenix.AuthorizationServer.BackchannelAuthentication`
[🔗](https://github.com/XukuLLC/attesto_phoenix/blob/v2.1.0/lib/attesto_phoenix/authorization_server/backchannel_authentication.ex#L1)

CIBA backchannel authentication request processing (OpenID Connect CIBA Core
1.0 §7), as conn-free core.

Turns an authenticated confidential client and a parsed backchannel
authentication request into the §7.3 acknowledgement (`auth_req_id`,
`expires_in`, `interval`), by:

1. building the core `Attesto.CIBA.Request.client()` map from the client's
   registered CIBA metadata (`AttestoPhoenix.Config.client_ciba_registration/2` + the shared
   `:client_id` / `:client_jwks` callbacks);
2. stripping the client-authentication parameters so a signed authentication
   request (§7.1.1) stands alone;
3. validating the request via `Attesto.CIBA.Request.validate/3` (scope, the
   exactly-one-hint rule, `binding_message`, and - for FAPI-CIBA - the
   mandatory signed `request` JWT against the client's JWKS);
4. guarding a signed request's `jti` against replay when the host wired a
   `:replay_check` seam (FAPI-CIBA §5.2.2 host obligation);
5. resolving the request's hint to an end-user through the host
   `:authenticate_ciba_user` callback (CIBA §7.1: the user is identified
   BEFORE the acknowledgement is returned) - which also verifies any
   `user_code`;
6. minting the `auth_req_id` via `Attesto.CIBA.issue/4`; and
7. kicking off the out-of-band authentication through the host
   `:notify_ciba_user` callback, fire-and-forget so the acknowledgement never
   waits on it.

The thin `AttestoPhoenix.Controller.BackchannelAuthenticationController` parses
the request off the `Plug.Conn`, authenticates the client (confidential only,
FAPI-CIBA §5.2.2), lifts the conn facts into a `%Request{}` of plain data, and
calls `request/2`. Every grant decision lives here or in the core.

# `response`

```elixir
@type response() :: %{required(atom()) =&gt; term()}
```

The CIBA §7.3 authentication request acknowledgement (atom keys; `:interval` dropped when nil).

# `request`

```elixir
@spec request(
  AttestoPhoenix.Config.t(),
  AttestoPhoenix.AuthorizationServer.BackchannelAuthentication.Request.t()
) :: {:ok, response()} | {:error, AttestoPhoenix.OAuthError.t()}
```

Process a backchannel authentication request, returning the §7.3
acknowledgement or an `AttestoPhoenix.OAuthError` (whose status is the CIBA
§13 status from `Attesto.CIBA.error_status/1`).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
