# `AttestoPhoenix.AuthorizationServer.DeviceAuthorization`
[🔗](https://github.com/XukuLLC/attesto_phoenix/blob/v0.19.1/lib/attesto_phoenix/authorization_server/device_authorization.ex#L1)

Device authorization request processing (RFC 8628 §3.1 / §3.2), as conn-free
core.

Turns an authenticated client and a parsed device-authorization request into
the RFC 8628 §3.2 response body (`device_code`, `user_code`,
`verification_uri`, `verification_uri_complete`, `expires_in`, `interval`),
binding the requested `scope`, the RFC 8707 `resource` indicator(s), and — when
presented — the RFC 9449 DPoP holder-of-key onto the issued device code. The
thin `AttestoPhoenix.Controller.DeviceAuthorizationController` parses the
request off the `Plug.Conn`, authenticates the client (RFC 6749 §2.3), lifts
the conn facts into a `%Request{}` of plain data, and calls `request/2`.

## DPoP for public clients (security)

A device code travels on a pollable channel with no PKCE backstop and no
redirect to bind, so a public (`:none`) client's resulting token would be a
freely-replayable bearer token. Mirroring the public-client refresh-token rule
(RFC 9449 §8), a public client MUST present a DPoP proof at this endpoint; the
proof's key is pre-bound to the device code and the token endpoint requires the
matching proof at redemption. Confidential clients may opt out.

# `response`

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

The RFC 8628 §3.2 device-authorization response body (atom keys).

# `request`

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

Process a device-authorization request, returning the §3.2 response body or an
`AttestoPhoenix.OAuthError`.

---

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