-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtoken.php
More file actions
126 lines (102 loc) · 4.28 KB
/
Copy pathtoken.php
File metadata and controls
126 lines (102 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<?php
declare(strict_types=1);
/**
* IndieAuth token endpoint.
*
* POST grant_type=authorization_code — exchange a code (issued by
* /indieauth.php) for a scoped bearer access token.
* POST ?action=revoke (or action=revoke in the body) — revoke a token.
* Always responds 200 per spec.
* POST ?action=introspect — token introspection for resource servers.
* Requires a valid bearer token to call.
* GET with Authorization: Bearer — legacy token verification, returns
* {me, client_id, scope} for older Micropub clients.
*/
// Never render a PHP notice or fatal into the response: it would leak absolute
// filesystem paths, and on the JSON endpoints it also corrupts the body. Errors
// still reach the server log.
ini_set('display_errors', '0');
define('CMS_ROOT', __DIR__);
require CMS_ROOT . '/vendor/autoload.php';
use CMS\IndieAuth;
use CMS\MicropubAuth;
$config = require CMS_ROOT . '/config.php';
$db = new \CMS\Database($config['paths']['data'] . '/cms.db');
$indie = new IndieAuth($db);
$siteUrl = rtrim($db->getSetting('site_url', ''), '/');
$me = $siteUrl . '/';
header('Cache-Control: no-store');
header('Pragma: no-cache');
// ── GET: legacy token verification ───────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$authz = MicropubAuth::authenticate($db, $config);
MicropubAuth::json([
'me' => $authz['me'],
'client_id' => $authz['client_id'] ?? '',
'scope' => implode(' ', $authz['scopes']),
]);
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header('Allow: GET, POST');
MicropubAuth::error('invalid_request', 'Method not allowed', 405);
}
$action = (string) ($_GET['action'] ?? ($_POST['action'] ?? ''));
// ── POST: revocation ─────────────────────────────────────────────────────────
if ($action === 'revoke') {
$indie->revokeToken((string) ($_POST['token'] ?? ''));
// Spec: the endpoint responds 200 whether or not the token was valid.
MicropubAuth::json(new stdClass());
}
// ── POST: introspection ──────────────────────────────────────────────────────
if ($action === 'introspect') {
MicropubAuth::authenticate($db, $config);
$subject = (string) ($_POST['token'] ?? '');
if (MicropubAuth::legacyTokenMatches($db->getSetting('micropub_token', ''), $subject)) {
MicropubAuth::json([
'active' => true,
'me' => $me,
'client_id' => '',
'scope' => implode(' ', IndieAuth::SCOPES),
]);
}
$row = $indie->verifyToken($subject);
if (!$row) {
MicropubAuth::json(['active' => false]);
}
MicropubAuth::json([
'active' => true,
'me' => (string) $row['me'],
'client_id' => (string) $row['client_id'],
'scope' => (string) $row['scope'],
]);
}
// ── POST: authorization-code exchange ────────────────────────────────────────
$grantType = (string) ($_POST['grant_type'] ?? '');
if ($grantType !== 'authorization_code') {
MicropubAuth::error('unsupported_grant_type', 'grant_type must be authorization_code');
}
$row = $indie->redeemCode(
(string) ($_POST['code'] ?? ''),
(string) ($_POST['client_id'] ?? ''),
(string) ($_POST['redirect_uri'] ?? ''),
(string) ($_POST['code_verifier'] ?? '')
);
if (!$row) {
MicropubAuth::error('invalid_grant', 'authorization code is invalid, expired, or already used');
}
$scope = trim((string) $row['scope']);
if ($scope === '') {
MicropubAuth::error('invalid_grant', 'no scope was granted; redeem sign-in codes at the authorization endpoint');
}
$token = $indie->issueToken(
(string) $row['client_id'],
(string) ($row['client_name'] ?? ''),
(string) $row['me'],
$scope
);
MicropubAuth::json([
'access_token' => $token,
'token_type' => 'Bearer',
'scope' => $scope,
'me' => (string) $row['me'],
]);