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
48 lines
1.1 KiB
PHP
48 lines
1.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Attributes\Fillable;
|
|
use Illuminate\Database\Eloquent\Attributes\Table;
|
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
#[Table('micropub_tokens')]
|
|
#[Fillable(['token_hash', 'client_id', 'me', 'scope'])]
|
|
class MicropubToken extends Model
|
|
{
|
|
protected function casts(): array
|
|
{
|
|
return [
|
|
'revoked_at' => 'datetime',
|
|
];
|
|
}
|
|
|
|
public function revoke(): void
|
|
{
|
|
$this->forceFill(['revoked_at' => now()])->save();
|
|
}
|
|
|
|
/**
|
|
* Find the active (non-revoked) token matching a raw bearer token string.
|
|
*/
|
|
public static function findActive(string $rawToken): ?self
|
|
{
|
|
if ($rawToken === '') {
|
|
return null;
|
|
}
|
|
|
|
return self::where('token_hash', hash('sha256', $rawToken))
|
|
->whereNull('revoked_at')
|
|
->first();
|
|
}
|
|
|
|
protected function isRevoked(): Attribute
|
|
{
|
|
return Attribute::make(
|
|
get: fn () => $this->revoked_at !== null,
|
|
);
|
|
}
|
|
}
|