4 if (file_exists(__DIR__ . '/../src/shpub/Autoloader.php')) {
5 include_once __DIR__ . '/../src/shpub/Autoloader.php';
6 Autoloader::register();
12 * @link http://micropub.net/draft/
13 * @link http://indieweb.org/authorization-endpoint
15 $server = 'http://anoweco.bogo/';
16 $user = 'http://anoweco.bogo/user/3.htm';
18 require_once 'HTTP/Request2.php';
20 $endpoints = discoverEndpoints($server);
21 list($accessToken, $userUrl) = getAuthCode($user, $endpoints);
22 var_dump($endpoints, $accessToken, $userUrl);
25 function getAuthCode($user, $endpoints)
27 //fetch temporary authorization token
28 $redirect_uri = 'http://127.0.0.1:12345/callback';
30 $client_id = 'http://cweiske.de/shpub.htm';
32 $browserUrl = $endpoints->authorization
33 . '?me=' . urlencode($user)
34 . '&client_id=' . urlencode($client_id)
35 . '&redirect_uri=' . urlencode($redirect_uri)
38 . '&response_type=code';
39 echo "To authenticate, open the following URL:\n"
42 $authParams = startHttpServer();
44 if ($authParams['state'] != $state) {
45 logError('Wrong "state" parameter value');
49 //verify indieauth params
50 $req = new HTTP_Request2($endpoints->authorization, 'POST');
51 $req->setHeader('Content-Type: application/x-www-form-urlencoded');
55 'code' => $authParams['code'],
57 'client_id' => $client_id,
58 'redirect_uri' => $redirect_uri,
63 if ($res->getHeader('content-type') != 'application/x-www-form-urlencoded') {
64 logError('Wrong content type in auth verification response');
67 parse_str($res->getBody(), $verifiedParams);
68 if (!isset($verifiedParams['me'])
69 || $verifiedParams['me'] !== $authParams['me']
71 logError('Non-matching "me" values');
75 $userUrl = $verifiedParams['me'];
78 //fetch permanent access token
79 $req = new HTTP_Request2($endpoints->token, 'POST');
80 $req->setHeader('Content-Type: application/x-www-form-urlencoded');
85 'code' => $authParams['code'],
86 'redirect_uri' => $redirect_uri,
87 'client_id' => $client_id,
93 if ($res->getHeader('content-type') != 'application/x-www-form-urlencoded') {
94 logError('Wrong content type in auth verification response');
97 parse_str($res->getBody(), $tokenParams);
98 if (!isset($tokenParams['access_token'])) {
99 logError('"access_token" missing');
103 $accessToken = $tokenParams['access_token'];
105 return [$accessToken, $userUrl];
108 function startHttpServer()
110 $responseOk = "HTTP/1.0 200 OK\r\n"
111 . "Content-Type: text/plain\r\n"
113 . "Ok. You may close this tab and return to the shell.\r\n";
114 $responseErr = "HTTP/1.0 400 Bad Request\r\n"
115 . "Content-Type: text/plain\r\n"
119 //5 minutes should be enough for the user to confirm
120 ini_set('default_socket_timeout', 60 * 5);
121 $server = stream_socket_server(
122 'tcp://127.0.0.1:12345', $errno, $errstr
130 $sock = stream_socket_accept($server);
139 //read request headers
140 while (false !== ($line = trim(fgets($sock)))) {
144 if (preg_match('#^Content-Length:\s*([[:digit:]]+)\s*$#i', $line, $matches)) {
145 $content_length = (int) $matches[1];
151 if ($content_length > 0) {
152 $body = fread($sock, $content_length);
156 list($method, $url, $httpver) = explode(' ', $headers[0]);
157 if ($method == 'GET') {
158 $parts = parse_url($url);
159 if (isset($parts['path']) && $parts['path'] == '/callback'
160 && isset($parts['query'])
162 parse_str($parts['query'], $query);
163 if (isset($query['code'])
164 && isset($query['state'])
165 && isset($query['me'])
167 fwrite($sock, $responseOk);
174 fwrite($sock, $responseErr);
179 class Config_Endpoints
184 public $authorization;
187 function discoverEndpoints($url)
189 $cfg = new Config_Endpoints();
191 //TODO: discovery via link headers
193 $sx = simplexml_load_file($url);
194 $sx->registerXPathNamespace('h', 'http://www.w3.org/1999/xhtml');
197 '/h:html/h:head/h:link[@rel="authorization_endpoint" and @href]'
199 if (!count($auths)) {
200 logError('No authorization endpoint found');
203 $cfg->authorization = (string) $auths[0]['href'];
205 $tokens = $sx->xpath(
206 '/h:html/h:head/h:link[@rel="token_endpoint" and @href]'
208 if (!count($tokens)) {
209 logError('No token endpoint found');
212 $cfg->token = (string) $tokens[0]['href'];
215 '/h:html/h:head/h:link[@rel="micropub" and @href]'
218 logError('No micropub endpoint found');
221 $cfg->micropub = (string) $mps[0]['href'];
226 function logError($msg)
228 file_put_contents('php://stderr', $msg . "\n", FILE_APPEND);