Server
Server
Authorization server engine implementing the MCP Authorization subset of OAuth 2.1.
class Server extends \Hazaar\ControllerExtends: Hazaar\Controller
Extend this (normally via Hazaar\Controller\OAuth) to turn an application into an MCP OAuth authorization server. The engine owns protocol mechanics only:
- Hazaar\OAuth\Server::metadata: RFC 8414 metadata document (
/.well-known/oauth-authorization-server) - Hazaar\OAuth\Server::authorize: the authorization code + PKCE front-channel flow (
/authorize) - Hazaar\OAuth\Server::token: the
authorization_codeandrefresh_tokengrants, plus the RFC 8628device_codegrant when enabled (/token) - Hazaar\OAuth\Server::register: RFC 7591 dynamic client registration (
/register) - Hazaar\OAuth\Server::deviceAuthorization / Hazaar\OAuth\Server::deviceVerify: the RFC 8628 device authorization grant, for input-constrained or browserless clients (opt-in via
oauth.server.device_authorization_enabled)
How users log in and how consent is presented are the application's responsibility, delegated through two hooks:
- Hazaar\OAuth\Server::authenticatedUser — defaults to delegating to Hazaar\Auth\Adapter, override if the app resolves the current user differently.
- Hazaar\OAuth\Server::consent — abstract; the app implements the consent UI and returns a Hazaar\OAuth\ConsentDecision.
Persistence is delegated to three storage interfaces the app binds via config (oauth.server.clients, oauth.server.codes, oauth.server.refresh_tokens): Hazaar\OAuth\Interface\ClientRepository, Hazaar\OAuth\Interface\AuthorizationCodeStore, Hazaar\OAuth\Interface\RefreshTokenStore. Ready-to-use DBI-backed implementations are provided under Hazaar\OAuth\Store\DBI.
Access tokens are JWTs (RS256 by default) minted and verified with the existing Hazaar\Auth\Session\Backend\JWT machinery — configure signing/verification key material under oauth.server.jwt exactly as you would for auth.jwt. Refresh tokens are deliberately not JWTs: they are opaque, store-backed, and rotated on every use, because — unlike access tokens — they are only ever presented back to this server and must be revocable.
Properties
config
protected Options $configType: Hazaar\OAuth\Server\Options
clients
protected ClientRepository $clientsType: Hazaar\OAuth\Interface\ClientRepository
codes
protected AuthorizationCodeStore $codesType: Hazaar\OAuth\Interface\AuthorizationCodeStore
refreshTokens
protected RefreshTokenStore $refreshTokensType: Hazaar\OAuth\Interface\RefreshTokenStore
deviceCodeStore
public DeviceAuthorizationStore $deviceCodeStoreType: Hazaar\OAuth\Interface\DeviceAuthorizationStore
jwt
private JWT $jwtType: Hazaar\Auth\Session\Backend\JWT
Methods
__construct
public __construct(Request $request): voidParameters
| Parameter | Type | Description |
|---|---|---|
$request | Hazaar\Application\Request |
metadata
RFC 8414 authorization server metadata document.
public metadata(): Response\JSONReturns: Hazaar\Controller\Response\JSON
Mount at /.well-known/oauth-authorization-server.
authorize
The authorization code + PKCE front-channel flow.
public authorize(): ResponseReturns: Hazaar\Controller\Response
Mount at /authorize (GET, and POST for consent form resubmission).
token
The authorization_code and refresh_token token grants.
public token(): Response\JSONReturns: Hazaar\Controller\Response\JSON
Mount at /token (POST).
register
RFC 7591 dynamic client registration.
public register(): Response\JSONReturns: Hazaar\Controller\Response\JSON
Mount at /register (POST).
deviceAuthorization
RFC 8628 device authorization endpoint: a client that can't receive a redirect (a CLI, an
public deviceAuthorization(): Response\JSONReturns: Hazaar\Controller\Response\JSON
extension sandbox, a TV) starts the flow here and gets a device code to poll /token with, plus a short user code for the user to confirm at the verification URI.
Mount at /device_authorization (POST). Requires device_authorization_enabled.
deviceVerify
The user's side of the device flow: an authenticated user approves or denies the device
public deviceVerify(): ResponseReturns: Hazaar\Controller\Response
authorization identified by user_code. The application's verification page (the device_verification_uri) submits here; the decision comes from Hazaar\OAuth\Server::deviceConsent.
Responds with JSON ({"status": "approved"|"denied", "client_name": ...}) rather than a redirect, since there's no client redirect URI in this flow. An unauthenticated user is sent to the login page, as with Hazaar\OAuth\Server::authorize.
Mount at the path the verification page submits to (GET and POST). Requires device_authorization_enabled.
normalizeUserCode
Normalizes a user code as typed by a user: case-insensitive, and ignoring the separator and
public normalizeUserCode(string $userCode): stringReturns: string
any spaces, so "bcdf-ghjk", "BCDF GHJK" and "BCDFGHJK" all name the same code.
Parameters
| Parameter | Type | Description |
|---|---|---|
$userCode | string |
loadConfig
Loads the oauth.server configuration section.
protected loadConfig(): arrayReturns: array
Override to source configuration some other way (e.g. in tests, to inject fake stores or key material directly instead of round-tripping through app config files).
authenticatedUser
Resolves the currently authenticated user for the /authorize step.
protected authenticatedUser(): ?stringReturns: string
Defaults to delegating to Hazaar\Auth\Adapter: the app's own login flow is whatever populates that adapter's session (username/password, SSO, etc.) — this component only cares whether a user is authenticated. Override if the app resolves identity some other way.
redirectToLogin
Redirects an unauthenticated user to the application's login page.
protected redirectToLogin(): ResponseReturns: Hazaar\Controller\Response
The original /authorize request (including all query parameters) is preserved in a return_to parameter, so the app's login flow can bounce the user straight back once they've authenticated.
consent
protected consent(Client $client, array $scope, string $userIdentity): ConsentDecisionReturns: Hazaar\OAuth\ConsentDecision
Parameters
| Parameter | Type | Description |
|---|---|---|
$client | Hazaar\OAuth\Client | |
$scope | array | |
$userIdentity | string |
deviceConsent
The consent hook for the device flow (Hazaar\OAuth\Server::deviceVerify).
protected deviceConsent(DeviceAuthorization $authorization, Client $client, string $userIdentity): ConsentDecisionReturns: Hazaar\OAuth\ConsentDecision
Defaults to Hazaar\OAuth\Server::consent. Override when the application's consent UI for a device (confirming a user code, with no redirect URI involved) differs from its /authorize one.
Parameters
| Parameter | Type | Description |
|---|---|---|
$authorization | Hazaar\OAuth\DeviceAuthorization | |
$client | Hazaar\OAuth\Client | |
$userIdentity | string |
issueAccessToken
Mints a signed JWT access token via the shared Hazaar\Auth\Session\Backend\JWT machinery.
protected issueAccessToken(string $userIdentity, string $clientId, array $scope, ?string $resource): ExpiringTokenReturns: Hazaar\Auth\ExpiringToken
Parameters
| Parameter | Type | Description |
|---|---|---|
$userIdentity | string | |
$clientId | string | |
$scope | array | |
$resource | string |
issueRefreshToken
Issues a new opaque, store-backed refresh token.
protected issueRefreshToken(string $userIdentity, string $clientId, array $scope, ?string $resource): RefreshTokenReturns: Hazaar\OAuth\RefreshToken
Parameters
| Parameter | Type | Description |
|---|---|---|
$userIdentity | string | |
$clientId | string | |
$scope | array | |
$resource | string |
grantAuthorizationCode
private grantAuthorizationCode(array $body): arrayReturns: array
Parameters
| Parameter | Type | Description |
|---|---|---|
$body | array |
grantRefreshToken
private grantRefreshToken(array $body): arrayReturns: array
Parameters
| Parameter | Type | Description |
|---|---|---|
$body | array |
grantDeviceCode
The RFC 8628 device_code grant: the device polls until the user has decided.
private grantDeviceCode(array $body): arrayReturns: array
Parameters
| Parameter | Type | Description |
|---|---|---|
$body | array |
requireDeviceGrant
private requireDeviceGrant(): voidReturns: void
deviceCodes
private deviceCodes(): DeviceAuthorizationStoreReturns: Hazaar\OAuth\Interface\DeviceAuthorizationStore
generateUserCode
A user code: 8 letters from the RFC 8628 §6.1 consonant-only alphabet (no vowels, so codes
private generateUserCode(): stringReturns: string
can't spell words; no easily-confused characters), ~34 bits of entropy -- ample for a code that expires in minutes and can be guessed at only by an authenticated user.
formatUserCode
The user-facing form of a user code: "BCDF-GHJK".
private formatUserCode(string $userCode): stringReturns: string
Parameters
| Parameter | Type | Description |
|---|---|---|
$userCode | string |
verificationURI
private verificationURI(): stringReturns: string
authenticateClient
Authenticates the client presenting a /token request.
private authenticateClient(array $body): ClientReturns: Hazaar\OAuth\Client
Accepts client_secret_basic (HTTP Basic authorization header) or client_secret_post (client_id/client_secret in the body). Public clients (token_endpoint_auth_method === 'none') are identified by client_id alone and rely on PKCE instead.
Parameters
| Parameter | Type | Description |
|---|---|---|
$body | array |
verifyPKCE
private verifyPKCE(string $codeChallenge, string $codeVerifier): boolReturns: bool
Parameters
| Parameter | Type | Description |
|---|---|---|
$codeChallenge | string | |
$codeVerifier | string |
parseScope
private parseScope(?string $scope): arrayReturns: array
Parameters
| Parameter | Type | Description |
|---|---|---|
$scope | string |
bodyParams
private bodyParams(): arrayReturns: array
requireParam
private requireParam(string $key): stringReturns: string
Parameters
| Parameter | Type | Description |
|---|---|---|
$key | string |
redirectWithParams
private redirectWithParams(string $redirectUri, array $params): ResponseReturns: Hazaar\Controller\Response
Parameters
| Parameter | Type | Description |
|---|---|---|
$redirectUri | string | |
$params | array |
issuer
private issuer(): stringReturns: string
endpointURL
private endpointURL(string $path): stringReturns: string
Parameters
| Parameter | Type | Description |
|---|---|---|
$path | string |
resolveStore
Instantiates a store bound via config, which may be a class-string (constructed with the
private resolveStore(object|string $binding, string $interface, array $options): objectReturns: object
given options) or an already-built instance.
Parameters
| Parameter | Type | Description |
|---|---|---|
$binding | object | string |
$interface | string | |
$options | array |
Generated by Hazaar API Doc Generator on Thu, 22 Oct 2026 05:05:28 +0000