Add IndieAuth token introspection endpoint (RFC 7662)
Lets a resource server (or a client checking its own token, via
self-introspection) verify a token's active/me/client_id/scope without
needing to be tightly coupled to this token endpoint. Requires the
caller to present their own currently-active token as authorization,
per spec's requirement that the endpoint MUST require some form of
authorization. Inactive tokens get back only {"active": false}, no
detail on why, matching the privacy stance already used for
revocation.
Pulled the hash-and-lookup-active-token logic (now needed a third
time) into MicropubToken::findActive(), used by this, the revocation
endpoint, and VerifyMicropubToken.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014625MfkGZ7GVdbqKme4a8L
This commit is contained in:
parent
9d6cf6c815
commit
24da24a677
5 changed files with 125 additions and 12 deletions
|
|
@ -26,9 +26,9 @@ class IndieAuthController extends Controller
|
|||
'authorization_endpoint' => route('indieauth.start'),
|
||||
'token_endpoint' => route('indieauth.token'),
|
||||
'revocation_endpoint' => route('indieauth.revocation'),
|
||||
'introspection_endpoint' => route('indieauth.introspection'),
|
||||
'introspection_endpoint_auth_methods_supported' => ['Bearer'],
|
||||
'code_challenge_methods_supported' => ['S256'],
|
||||
// 'introspection_endpoint' => route('indieauth.introspection'),
|
||||
// 'introspection_endpoint_auth_methods_supported' => ['none'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -188,18 +188,42 @@ class IndieAuthController extends Controller
|
|||
*/
|
||||
public function processRevocationRequest(Request $request): JsonResponse
|
||||
{
|
||||
$token = $request->get('token', '');
|
||||
|
||||
if ($token !== '') {
|
||||
MicropubToken::where('token_hash', hash('sha256', $token))
|
||||
->whereNull('revoked_at')
|
||||
->first()
|
||||
?->revoke();
|
||||
}
|
||||
MicropubToken::findActive($request->get('token', ''))?->revoke();
|
||||
|
||||
return response()->json([], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a POST request to the IndieAuth token introspection endpoint
|
||||
* (RFC 7662, extended by IndieAuth to require the `me` property).
|
||||
*
|
||||
* The caller must itself present a currently-active token as a Bearer
|
||||
* credential to use this endpoint, per spec ("MUST also require some
|
||||
* form of authorization"). Per spec, an inactive token being introspected
|
||||
* still gets a 200 response containing only `active: false` - no other
|
||||
* information about why it's inactive is given.
|
||||
*/
|
||||
public function processIntrospectionRequest(Request $request): JsonResponse
|
||||
{
|
||||
if (! MicropubToken::findActive((string) $request->bearerToken())) {
|
||||
return response()->json([], 401);
|
||||
}
|
||||
|
||||
$token = MicropubToken::findActive((string) $request->get('token', ''));
|
||||
|
||||
if (! $token) {
|
||||
return response()->json(['active' => false]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'active' => true,
|
||||
'me' => $token->me,
|
||||
'client_id' => $token->client_id,
|
||||
'scope' => $token->scope,
|
||||
'iat' => $token->created_at->timestamp,
|
||||
]);
|
||||
}
|
||||
|
||||
protected function isValidRedirectUri(string $clientId, string $redirectUri): bool
|
||||
{
|
||||
// If client_id is not a valid URL, then it's not valid
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@ class VerifyMicropubToken
|
|||
], 401);
|
||||
}
|
||||
|
||||
$token = MicropubToken::where('token_hash', hash('sha256', $rawToken))
|
||||
->whereNull('revoked_at')
|
||||
->first();
|
||||
$token = MicropubToken::findActive($rawToken);
|
||||
|
||||
if (! $token) {
|
||||
$micropubResponses = new MicropubResponses;
|
||||
|
|
|
|||
Loading…
Reference in a new issue