This repository has been archived on 2023-08-20. You can view files and clone it, but cannot push or open issues or pull requests.
indieauth/docs/coverage/Storage/FilesystemJsonStorage.php.html

679 lines
236 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Code Coverage for /Users/barnabywalters/Documents/Programming/taproot/indieauth/src/Storage/FilesystemJsonStorage.php</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="../_css/bootstrap.min.css" rel="stylesheet" type="text/css">
<link href="../_css/octicons.css" rel="stylesheet" type="text/css">
<link href="../_css/style.css" rel="stylesheet" type="text/css">
<link href="../_css/custom.css" rel="stylesheet" type="text/css">
</head>
<body>
<header>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="../index.html">/Users/barnabywalters/Documents/Programming/taproot/indieauth/src</a></li>
<li class="breadcrumb-item"><a href="index.html">Storage</a></li>
<li class="breadcrumb-item active">FilesystemJsonStorage.php</li>
</ol>
</nav>
</div>
</div>
</div>
</header>
<div class="container-fluid">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<td>&nbsp;</td>
<td colspan="10"><div align="center"><strong>Code Coverage</strong></div></td>
</tr>
<tr>
<td>&nbsp;</td>
<td colspan="3"><div align="center"><strong>Classes and Traits</strong></div></td>
<td colspan="4"><div align="center"><strong>Functions and Methods</strong></div></td>
<td colspan="3"><div align="center"><strong>Lines</strong></div></td>
</tr>
</thead>
<tbody>
<tr>
<td class="danger">Total</td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="warning big"> <div class="progress">
<div class="progress-bar bg-warning" role="progressbar" aria-valuenow="53.85" aria-valuemin="0" aria-valuemax="100" style="width: 53.85%">
<span class="sr-only">53.85% covered (warning)</span>
</div>
</div>
</td>
<td class="warning small"><div align="right">53.85%</div></td>
<td class="warning small"><div align="right">7&nbsp;/&nbsp;13</div></td>
<td class="warning small"><abbr title="Change Risk Anti-Patterns (CRAP) Index">CRAP</abbr></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="92.31" aria-valuemin="0" aria-valuemax="100" style="width: 92.31%">
<span class="sr-only">92.31% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">92.31%</div></td>
<td class="success small"><div align="right">96&nbsp;/&nbsp;104</div></td>
</tr>
<tr>
<td class="danger"><abbr title="Taproot\IndieAuth\Storage\FilesystemJsonStorage">FilesystemJsonStorage</abbr></td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="warning big"> <div class="progress">
<div class="progress-bar bg-warning" role="progressbar" aria-valuenow="53.85" aria-valuemin="0" aria-valuemax="100" style="width: 53.85%">
<span class="sr-only">53.85% covered (warning)</span>
</div>
</div>
</td>
<td class="warning small"><div align="right">53.85%</div></td>
<td class="warning small"><div align="right">7&nbsp;/&nbsp;13</div></td>
<td class="warning small">48.01</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="92.31" aria-valuemin="0" aria-valuemax="100" style="width: 92.31%">
<span class="sr-only">92.31% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">92.31%</div></td>
<td class="success small"><div align="right">96&nbsp;/&nbsp;104</div></td>
</tr>
<tr>
<td class="danger" colspan="4">&nbsp;<a href="#40"><abbr title="__construct(string $path, string $secret, ?int $authCodeTtl, ?int $accessTokenTtl, $cleanUpNow, ?Psr\Log\LoggerInterface $logger)">__construct</abbr></a></td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="danger small">4.10</td>
<td class="warning big"> <div class="progress">
<div class="progress-bar bg-warning" role="progressbar" aria-valuenow="81.82" aria-valuemin="0" aria-valuemax="100" style="width: 81.82%">
<span class="sr-only">81.82% covered (warning)</span>
</div>
</div>
</td>
<td class="warning small"><div align="right">81.82%</div></td>
<td class="warning small"><div align="right">9&nbsp;/&nbsp;11</div></td>
</tr>
<tr>
<td class="success" colspan="4">&nbsp;<a href="#62"><abbr title="setLogger(Psr\Log\LoggerInterface $logger)">setLogger</abbr></a></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
<td class="success small">1</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">2&nbsp;/&nbsp;2</div></td>
</tr>
<tr>
<td class="danger" colspan="4">&nbsp;<a href="#68"><abbr title="createAuthCode(array $data): ?string">createAuthCode</abbr></a></td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="danger small">3.03</td>
<td class="warning big"> <div class="progress">
<div class="progress-bar bg-warning" role="progressbar" aria-valuenow="85.71" aria-valuemin="0" aria-valuemax="100" style="width: 85.71%">
<span class="sr-only">85.71% covered (warning)</span>
</div>
</div>
</td>
<td class="warning small"><div align="right">85.71%</div></td>
<td class="warning small"><div align="right">6&nbsp;/&nbsp;7</div></td>
</tr>
<tr>
<td class="danger" colspan="4">&nbsp;<a href="#82"><abbr title="exchangeAuthCodeForAccessToken(string $code, callable $validateAuthCode): ?array">exchangeAuthCodeForAccessToken</abbr></a></td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="danger small">11.04</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="92.86" aria-valuemin="0" aria-valuemax="100" style="width: 92.86%">
<span class="sr-only">92.86% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">92.86%</div></td>
<td class="success small"><div align="right">26&nbsp;/&nbsp;28</div></td>
</tr>
<tr>
<td class="success" colspan="4">&nbsp;<a href="#147"><abbr title="getAccessToken(string $token): ?array">getAccessToken</abbr></a></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
<td class="success small">5</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">5&nbsp;/&nbsp;5</div></td>
</tr>
<tr>
<td class="success" colspan="4">&nbsp;<a href="#163"><abbr title="revokeAccessToken(string $token): bool">revokeAccessToken</abbr></a></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
<td class="success small">1</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
</tr>
<tr>
<td class="success" colspan="4">&nbsp;<a href="#169"><abbr title="deleteExpiredTokens(): int">deleteExpiredTokens</abbr></a></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
<td class="success small">9</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">13&nbsp;/&nbsp;13</div></td>
</tr>
<tr>
<td class="danger" colspan="4">&nbsp;<a href="#197"><abbr title="get(string $key): ?array">get</abbr></a></td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="danger small">4.01</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="91.67" aria-valuemin="0" aria-valuemax="100" style="width: 91.67%">
<span class="sr-only">91.67% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">91.67%</div></td>
<td class="success small"><div align="right">11&nbsp;/&nbsp;12</div></td>
</tr>
<tr>
<td class="success" colspan="4">&nbsp;<a href="#219"><abbr title="put(string $key, array $data): bool">put</abbr></a></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
<td class="success small">1</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">4&nbsp;/&nbsp;4</div></td>
</tr>
<tr>
<td class="danger" colspan="4">&nbsp;<a href="#228"><abbr title="delete(string $key, $observeLock): bool">delete</abbr></a></td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="danger small">3.02</td>
<td class="warning big"> <div class="progress">
<div class="progress-bar bg-warning" role="progressbar" aria-valuenow="87.50" aria-valuemin="0" aria-valuemax="100" style="width: 87.50%">
<span class="sr-only">87.50% covered (warning)</span>
</div>
</div>
</td>
<td class="warning small"><div align="right">87.50%</div></td>
<td class="warning small"><div align="right">7&nbsp;/&nbsp;8</div></td>
</tr>
<tr>
<td class="success" colspan="4">&nbsp;<a href="#242"><abbr title="getPath(string $key): string">getPath</abbr></a></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
<td class="success small">1</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
</tr>
<tr>
<td class="danger" colspan="4">&nbsp;<a href="#247"><abbr title="withLock(string $path, string $mode, callable $callback)">withLock</abbr></a></td>
<td class="danger big"> <div class="progress">
<div class="progress-bar bg-danger" role="progressbar" aria-valuenow="0.00" aria-valuemin="0" aria-valuemax="100" style="width: 0.00%">
<span class="sr-only">0.00% covered (danger)</span>
</div>
</div>
</td>
<td class="danger small"><div align="right">0.00%</div></td>
<td class="danger small"><div align="right">0&nbsp;/&nbsp;1</div></td>
<td class="danger small">3.01</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="90.91" aria-valuemin="0" aria-valuemax="100" style="width: 90.91%">
<span class="sr-only">90.91% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">90.91%</div></td>
<td class="success small"><div align="right">10&nbsp;/&nbsp;11</div></td>
</tr>
<tr>
<td class="success" colspan="4">&nbsp;<a href="#271"><abbr title="hash(string $token): string">hash</abbr></a></td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
<td class="success small">1</td>
<td class="success big"> <div class="progress">
<div class="progress-bar bg-success" role="progressbar" aria-valuenow="100.00" aria-valuemin="0" aria-valuemax="100" style="width: 100.00%">
<span class="sr-only">100.00% covered (success)</span>
</div>
</div>
</td>
<td class="success small"><div align="right">100.00%</div></td>
<td class="success small"><div align="right">1&nbsp;/&nbsp;1</div></td>
</tr>
</tbody>
</table>
</div>
<table id="code" class="table table-borderless table-condensed">
<tbody>
<tr class=" d-flex"><td class="col-1 text-right"><a id="1" href="#1">1</a></td><td class="col-11 codeLine"><span class="default">&lt;?php&nbsp;</span><span class="keyword">declare</span><span class="keyword">(</span><span class="default">strict_types</span><span class="keyword">=</span><span class="default">1</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="2" href="#2">2</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="3" href="#3">3</a></td><td class="col-11 codeLine"><span class="keyword">namespace</span><span class="default">&nbsp;</span><span class="default">Taproot</span><span class="default">\</span><span class="default">IndieAuth</span><span class="default">\</span><span class="default">Storage</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="4" href="#4">4</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="5" href="#5">5</a></td><td class="col-11 codeLine"><span class="keyword">use</span><span class="default">&nbsp;</span><span class="default">DirectoryIterator</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="6" href="#6">6</a></td><td class="col-11 codeLine"><span class="keyword">use</span><span class="default">&nbsp;</span><span class="default">Exception</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="7" href="#7">7</a></td><td class="col-11 codeLine"><span class="keyword">use</span><span class="default">&nbsp;</span><span class="default">Psr</span><span class="default">\</span><span class="default">Log</span><span class="default">\</span><span class="default">LoggerAwareInterface</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="8" href="#8">8</a></td><td class="col-11 codeLine"><span class="keyword">use</span><span class="default">&nbsp;</span><span class="default">Psr</span><span class="default">\</span><span class="default">Log</span><span class="default">\</span><span class="default">LoggerInterface</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="9" href="#9">9</a></td><td class="col-11 codeLine"><span class="keyword">use</span><span class="default">&nbsp;</span><span class="default">Psr</span><span class="default">\</span><span class="default">Log</span><span class="default">\</span><span class="default">NullLogger</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="10" href="#10">10</a></td><td class="col-11 codeLine"><span class="keyword">use</span><span class="default">&nbsp;</span><span class="default">Taproot</span><span class="default">\</span><span class="default">IndieAuth</span><span class="default">\</span><span class="default">IndieAuthException</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="11" href="#11">11</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="12" href="#12">12</a></td><td class="col-11 codeLine"><span class="keyword">use</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">Taproot</span><span class="default">\</span><span class="default">IndieAuth</span><span class="default">\</span><span class="default">generateRandomString</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="13" href="#13">13</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="14" href="#14">14</a></td><td class="col-11 codeLine"><span class="comment">/**</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="15" href="#15">15</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;Filesystem&nbsp;JSON&nbsp;Token&nbsp;Storage</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="16" href="#16">16</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="17" href="#17">17</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;An&nbsp;implementation&nbsp;of&nbsp;`TokenStorageInterface`&nbsp;which&nbsp;stores&nbsp;authorization&nbsp;codes</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="18" href="#18">18</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;and&nbsp;access&nbsp;tokens&nbsp;in&nbsp;the&nbsp;filesystem&nbsp;as&nbsp;JSON&nbsp;files,&nbsp;and&nbsp;supports&nbsp;custom&nbsp;access</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="19" href="#19">19</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;token&nbsp;lifetimes.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="20" href="#20">20</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="21" href="#21">21</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;This&nbsp;is&nbsp;intended&nbsp;as&nbsp;a&nbsp;default,&nbsp;example&nbsp;implementation&nbsp;with&nbsp;minimal&nbsp;requirements.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="22" href="#22">22</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;In&nbsp;practise,&nbsp;most&nbsp;people&nbsp;should&nbsp;probably&nbsp;be&nbsp;using&nbsp;an&nbsp;SQLite3&nbsp;version&nbsp;of&nbsp;this</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="23" href="#23">23</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;which&nbsp;I&nbsp;havent&nbsp;written&nbsp;yet.&nbsp;I&nbsp;havent&nbsp;extensively&nbsp;documented&nbsp;this&nbsp;class,&nbsp;as&nbsp;it</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="24" href="#24">24</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*&nbsp;will&nbsp;likely&nbsp;be&nbsp;superceded&nbsp;by&nbsp;the&nbsp;SQLite&nbsp;version.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="25" href="#25">25</a></td><td class="col-11 codeLine"><span class="comment">&nbsp;*/</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="26" href="#26">26</a></td><td class="col-11 codeLine"><span class="keyword">class</span><span class="default">&nbsp;</span><span class="default">FilesystemJsonStorage</span><span class="default">&nbsp;</span><span class="keyword">implements</span><span class="default">&nbsp;</span><span class="default">TokenStorageInterface</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">LoggerAwareInterface</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="27" href="#27">27</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">const</span><span class="default">&nbsp;</span><span class="default">DEFAULT_AUTH_CODE_TTL</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">60</span><span class="default">&nbsp;</span><span class="keyword">*</span><span class="default">&nbsp;</span><span class="default">5</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="comment">//&nbsp;Five&nbsp;minutes.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="28" href="#28">28</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">const</span><span class="default">&nbsp;</span><span class="default">DEFAULT_ACCESS_TOKEN_TTL</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">60</span><span class="default">&nbsp;</span><span class="keyword">*</span><span class="default">&nbsp;</span><span class="default">60</span><span class="default">&nbsp;</span><span class="keyword">*</span><span class="default">&nbsp;</span><span class="default">24</span><span class="default">&nbsp;</span><span class="keyword">*</span><span class="default">&nbsp;</span><span class="default">7</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="comment">//&nbsp;One&nbsp;week.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="29" href="#29">29</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="30" href="#30">30</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">const</span><span class="default">&nbsp;</span><span class="default">TOKEN_LENGTH</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">64</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="31" href="#31">31</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="32" href="#32">32</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span class="default">&nbsp;</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$path</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="33" href="#33">33</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span class="default">&nbsp;</span><span class="default">int</span><span class="default">&nbsp;</span><span class="default">$authCodeTtl</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="34" href="#34">34</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span class="default">&nbsp;</span><span class="default">int</span><span class="default">&nbsp;</span><span class="default">$accessTokenTtl</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="35" href="#35">35</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span class="default">&nbsp;</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$secret</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="36" href="#36">36</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="37" href="#37">37</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span class="default">&nbsp;</span><span class="default">LoggerInterface</span><span class="default">&nbsp;</span><span class="default">$logger</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="38" href="#38">38</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="39" href="#39">39</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="40" href="#40">40</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">__construct</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$secret</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">?</span><span class="default">int</span><span class="default">&nbsp;</span><span class="default">$authCodeTtl</span><span class="keyword">=</span><span class="default">null</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">?</span><span class="default">int</span><span class="default">&nbsp;</span><span class="default">$accessTokenTtl</span><span class="keyword">=</span><span class="default">null</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$cleanUpNow</span><span class="keyword">=</span><span class="default">false</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">?</span><span class="default">LoggerInterface</span><span class="default">&nbsp;</span><span class="default">$logger</span><span class="keyword">=</span><span class="default">null</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 41" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="41" href="#41">41</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">logger</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$logger</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="keyword">new</span><span class="default">&nbsp;</span><span class="default">NullLogger</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="42" href="#42">42</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 43" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="43" href="#43">43</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">!</span><span class="default">is_string</span><span class="keyword">(</span><span class="default">$secret</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">||</span><span class="default">&nbsp;</span><span class="default">strlen</span><span class="keyword">(</span><span class="default">$secret</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">&lt;</span><span class="default">&nbsp;</span><span class="default">64</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="44" href="#44">44</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span class="default">&nbsp;</span><span class="keyword">new</span><span class="default">&nbsp;</span><span class="default">Exception</span><span class="keyword">(</span><span class="default">&quot;\$secret&nbsp;must&nbsp;be&nbsp;a&nbsp;string&nbsp;with&nbsp;a&nbsp;minimum&nbsp;length&nbsp;of&nbsp;64&nbsp;characters.&nbsp;Make&nbsp;one&nbsp;with&nbsp;Taproot\IndieAuth\generateRandomString(64)&quot;</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="45" href="#45">45</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 46" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="46" href="#46">46</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">secret</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$secret</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="47" href="#47">47</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 48" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="48" href="#48">48</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">path</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">rtrim</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">DIRECTORY_SEPARATOR</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">.</span><span class="default">&nbsp;</span><span class="default">DIRECTORY_SEPARATOR</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="49" href="#49">49</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 50" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="50" href="#50">50</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">authCodeTtl</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$authCodeTtl</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">self</span><span class="default">::</span><span class="default">DEFAULT_AUTH_CODE_TTL</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 51" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="51" href="#51">51</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">accessTokenTtl</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$accessTokenTtl</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">self</span><span class="default">::</span><span class="default">DEFAULT_ACCESS_TOKEN_TTL</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="52" href="#52">52</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 53" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="53" href="#53">53</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">@</span><span class="default">mkdir</span><span class="keyword">(</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">0777</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">true</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="54" href="#54">54</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 55" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="55" href="#55">55</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$cleanUpNow</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="56" href="#56">56</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">deleteExpiredTokens</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="57" href="#57">57</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="27 tests cover line 58" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="58" href="#58">58</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="59" href="#59">59</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="60" href="#60">60</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;LoggerAwareInterface&nbsp;method.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="61" href="#61">61</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="62" href="#62">62</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">setLogger</span><span class="keyword">(</span><span class="default">LoggerInterface</span><span class="default">&nbsp;</span><span class="default">$logger</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="25 tests cover line 63" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="63" href="#63">63</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">logger</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$logger</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="25 tests cover line 64" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidConfigRaisesException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthorizationRequestWithInvalidClientIdOrRedirectUriShowsErrorToUser&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testInvalidStateCodeChallengeOrScopeReturnErrorRedirects&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testHandlesValidAndInvalidMeUrlsCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testUnauthenticatedRequestReturnsAuthenticationResponse&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsServerErrorIfAuthenticationResultHasNoMeKey&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnErrorIfFetchingClientIdThrowsException&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdWithNoParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfRedirectUriDoesntMatchClientIdOrParsedRedirectUris&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdSufficientlyMatchesRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkHeaderRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsAuthorizationFormIfClientIdExactlyMatchesParsedLinkElementRedirectUri&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testFindsFirstHAppExactlyMatchingClientId&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasNoHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testReturnsErrorIfApprovalRequestHasInvalidHash&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorsIfParametersAreMissing&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorOnNonIndieauthRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testNonIndieAuthRequestWithDefaultHandlerReturnsError&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testResponseReturnedFromNonIndieAuthRequestHandler&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="64" href="#64">64</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="65" href="#65">65</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="66" href="#66">66</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TokenStorageInterface&nbsp;Methods.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="67" href="#67">67</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="68" href="#68">68</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">createAuthCode</span><span class="keyword">(</span><span class="keyword">array</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="keyword">?</span><span class="default">string</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="6 tests cover line 69" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="69" href="#69">69</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$authCode</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">generateRandomString</span><span class="keyword">(</span><span class="default">self</span><span class="default">::</span><span class="default">TOKEN_LENGTH</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="6 tests cover line 70" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="70" href="#70">70</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$accessToken</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">hash</span><span class="keyword">(</span><span class="default">$authCode</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="71" href="#71">71</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="6 tests cover line 72" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="72" href="#72">72</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">!</span><span class="default">array_key_exists</span><span class="keyword">(</span><span class="default">'valid_until'</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="6 tests cover line 73" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="73" href="#73">73</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">time</span><span class="keyword">(</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">+</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">authCodeTtl</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="74" href="#74">74</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="75" href="#75">75</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="6 tests cover line 76" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="76" href="#76">76</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">!</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">put</span><span class="keyword">(</span><span class="default">$accessToken</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="77" href="#77">77</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="78" href="#78">78</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="6 tests cover line 79" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="79" href="#79">79</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$authCode</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="80" href="#80">80</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="81" href="#81">81</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="82" href="#82">82</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">exchangeAuthCodeForAccessToken</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$code</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">callable</span><span class="default">&nbsp;</span><span class="default">$validateAuthCode</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="keyword">?</span><span class="keyword">array</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="83" href="#83">83</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Hash&nbsp;the&nbsp;auth&nbsp;code&nbsp;to&nbsp;get&nbsp;the&nbsp;theoretical&nbsp;matching&nbsp;access&nbsp;token&nbsp;filename.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 84" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="84" href="#84">84</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$accessToken</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">hash</span><span class="keyword">(</span><span class="default">$code</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="85" href="#85">85</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="86" href="#86">86</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Prevent&nbsp;the&nbsp;token&nbsp;file&nbsp;from&nbsp;being&nbsp;read,&nbsp;modified&nbsp;or&nbsp;deleted&nbsp;while&nbsp;were&nbsp;working&nbsp;with&nbsp;it.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="87" href="#87">87</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;r+&nbsp;to&nbsp;allow&nbsp;reading&nbsp;and&nbsp;writing,&nbsp;but&nbsp;to&nbsp;make&nbsp;sure&nbsp;we&nbsp;dont&nbsp;create&nbsp;the&nbsp;file&nbsp;if&nbsp;it&nbsp;doesnt&nbsp;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="88" href="#88">88</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;already&nbsp;exist.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 89" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="89" href="#89">89</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">withLock</span><span class="keyword">(</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">getPath</span><span class="keyword">(</span><span class="default">$accessToken</span><span class="keyword">)</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">'r+'</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">use</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$accessToken</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$validateAuthCode</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="90" href="#90">90</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Read&nbsp;the&nbsp;file&nbsp;contents.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 91" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="91" href="#91">91</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$fileContents</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">''</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 92" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="92" href="#92">92</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$d</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">fread</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">1024</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="default">$fileContents</span><span class="default">&nbsp;</span><span class="default">.=</span><span class="default">&nbsp;</span><span class="default">$d</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="93" href="#93">93</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 94" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="94" href="#94">94</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">json_decode</span><span class="keyword">(</span><span class="default">$fileContents</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">true</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="95" href="#95">95</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 96" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="96" href="#96">96</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">!</span><span class="default">is_array</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="97" href="#97">97</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="98" href="#98">98</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Make&nbsp;sure&nbsp;the&nbsp;auth&nbsp;code&nbsp;hasnt&nbsp;already&nbsp;been&nbsp;redeemed.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 99" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="99" href="#99">99</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'exchanged_at'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="100" href="#100">100</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="101" href="#101">101</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Make&nbsp;sure&nbsp;the&nbsp;auth&nbsp;code&nbsp;isnt&nbsp;expired.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 102" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="102" href="#102">102</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">0</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">&lt;</span><span class="default">&nbsp;</span><span class="default">time</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="103" href="#103">103</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="104" href="#104">104</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;auth&nbsp;code&nbsp;is&nbsp;valid&nbsp;as&nbsp;far&nbsp;as&nbsp;we&nbsp;know,&nbsp;pass&nbsp;it&nbsp;to&nbsp;the&nbsp;validation&nbsp;callback&nbsp;passed&nbsp;from&nbsp;the</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="105" href="#105">105</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Server.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="106" href="#106">106</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 107" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="107" href="#107">107</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$validateAuthCode</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="3 tests cover line 108" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="108" href="#108">108</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="default">&nbsp;</span><span class="keyword">catch</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">IndieAuthException</span><span class="default">&nbsp;</span><span class="default">$e</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="109" href="#109">109</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;If&nbsp;there&nbsp;was&nbsp;an&nbsp;issue&nbsp;with&nbsp;the&nbsp;auth&nbsp;code,&nbsp;delete&nbsp;it&nbsp;before&nbsp;bubbling&nbsp;the&nbsp;exception</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="110" href="#110">110</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;up&nbsp;to&nbsp;the&nbsp;Server&nbsp;for&nbsp;handling.&nbsp;We&nbsp;currently&nbsp;have&nbsp;a&nbsp;lock&nbsp;on&nbsp;the&nbsp;file&nbsp;path,&nbsp;so&nbsp;pass</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="111" href="#111">111</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;false&nbsp;to&nbsp;$observeLock&nbsp;to&nbsp;prevent&nbsp;a&nbsp;deadlock.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="3 tests cover line 112" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="112" href="#112">112</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">delete</span><span class="keyword">(</span><span class="default">$accessToken</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="3 tests cover line 113" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="113" href="#113">113</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span class="default">&nbsp;</span><span class="default">$e</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="114" href="#114">114</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="115" href="#115">115</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="116" href="#116">116</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;If&nbsp;the&nbsp;access&nbsp;token&nbsp;is&nbsp;valid,&nbsp;mark&nbsp;it&nbsp;as&nbsp;redeemed&nbsp;and&nbsp;set&nbsp;a&nbsp;new&nbsp;expiry&nbsp;time.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 117" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="117" href="#117">117</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'exchanged_at'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">time</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="118" href="#118">118</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 119" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="119" href="#119">119</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">is_int</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'_access_token_ttl'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="120" href="#120">120</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;This&nbsp;access&nbsp;token&nbsp;has&nbsp;a&nbsp;custom&nbsp;TTL,&nbsp;use&nbsp;that.</span></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="121" href="#121">121</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">time</span><span class="keyword">(</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">+</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'_access_code_ttl'</span><span class="keyword">]</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 122" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="122" href="#122">122</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="default">&nbsp;</span><span class="keyword">elseif</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">accessTokenTtl</span><span class="default">&nbsp;</span><span class="default">==</span><span class="default">&nbsp;</span><span class="default">0</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="123" href="#123">123</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;token&nbsp;should&nbsp;be&nbsp;valid&nbsp;until&nbsp;explicitly&nbsp;revoked.</span></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="124" href="#124">124</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="125" href="#125">125</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="default">&nbsp;</span><span class="keyword">else</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="126" href="#126">126</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Use&nbsp;the&nbsp;default&nbsp;TTL.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 127" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="127" href="#127">127</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">time</span><span class="keyword">(</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">+</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">accessTokenTtl</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="128" href="#128">128</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="129" href="#129">129</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="130" href="#130">130</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Write&nbsp;the&nbsp;new&nbsp;file&nbsp;contents,&nbsp;truncating&nbsp;afterwards&nbsp;in&nbsp;case&nbsp;the&nbsp;new&nbsp;data&nbsp;is&nbsp;shorter&nbsp;than&nbsp;the&nbsp;old&nbsp;data.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 131" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="131" href="#131">131</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$jsonData</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">json_encode</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 132" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="132" href="#132">132</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">rewind</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">===</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 133" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="133" href="#133">133</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">fwrite</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$jsonData</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">===</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 134" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="134" href="#134">134</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">ftruncate</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">strlen</span><span class="keyword">(</span><span class="default">$jsonData</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">===</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="135" href="#135">135</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="136" href="#136">136</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Return&nbsp;the&nbsp;OAuth2-compatible&nbsp;access&nbsp;token&nbsp;data&nbsp;to&nbsp;the&nbsp;Server&nbsp;for&nbsp;passing&nbsp;onto</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="137" href="#137">137</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;the&nbsp;client&nbsp;app.&nbsp;Passed&nbsp;via&nbsp;array_filter&nbsp;to&nbsp;remove&nbsp;the&nbsp;scope&nbsp;key&nbsp;if&nbsp;scope&nbsp;is&nbsp;null.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 138" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="138" href="#138">138</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">array_filter</span><span class="keyword">(</span><span class="keyword">[</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 139" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="139" href="#139">139</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">'access_token'</span><span class="default">&nbsp;</span><span class="default">=&gt;</span><span class="default">&nbsp;</span><span class="default">$accessToken</span><span class="keyword">,</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 140" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="140" href="#140">140</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">'scope'</span><span class="default">&nbsp;</span><span class="default">=&gt;</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'scope'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">,</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 141" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="141" href="#141">141</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">'me'</span><span class="default">&nbsp;</span><span class="default">=&gt;</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'me'</span><span class="keyword">]</span><span class="keyword">,</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 142" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="142" href="#142">142</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">'profile'</span><span class="default">&nbsp;</span><span class="default">=&gt;</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'profile'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">null</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="143" href="#143">143</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">]</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 144" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="144" href="#144">144</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="145" href="#145">145</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="146" href="#146">146</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="147" href="#147">147</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">getAccessToken</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$token</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="keyword">?</span><span class="keyword">array</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 148" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="148" href="#148">148</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">get</span><span class="keyword">(</span><span class="default">$token</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="149" href="#149">149</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 150" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="150" href="#150">150</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">!</span><span class="default">is_array</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="151" href="#151">151</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="152" href="#152">152</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Check&nbsp;that&nbsp;this&nbsp;is&nbsp;a&nbsp;redeemed&nbsp;access&nbsp;token.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 153" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="153" href="#153">153</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'exchanged_at'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">===</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="154" href="#154">154</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="155" href="#155">155</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Check&nbsp;that&nbsp;the&nbsp;access&nbsp;token&nbsp;is&nbsp;still&nbsp;valid.&nbsp;valid_until=null&nbsp;means&nbsp;it&nbsp;should&nbsp;live&nbsp;until</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="156" href="#156">156</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;explicitly&nbsp;revoked.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 157" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="157" href="#157">157</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">is_int</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">&amp;&amp;</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="keyword">&lt;</span><span class="default">&nbsp;</span><span class="default">time</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="158" href="#158">158</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="159" href="#159">159</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;The&nbsp;token&nbsp;is&nbsp;valid!</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 160" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="160" href="#160">160</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="161" href="#161">161</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="162" href="#162">162</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="163" href="#163">163</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">revokeAccessToken</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$token</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="default">bool</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 164" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="164" href="#164">164</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">delete</span><span class="keyword">(</span><span class="default">$token</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="165" href="#165">165</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="166" href="#166">166</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="167" href="#167">167</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Implementation-Specifc&nbsp;Methods.</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="168" href="#168">168</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="169" href="#169">169</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">deleteExpiredTokens</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="default">int</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 170" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="170" href="#170">170</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$deleted</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">0</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="171" href="#171">171</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 172" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="172" href="#172">172</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">foreach</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">new</span><span class="default">&nbsp;</span><span class="default">DirectoryIterator</span><span class="keyword">(</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">path</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">as</span><span class="default">&nbsp;</span><span class="default">$fileInfo</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 173" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="173" href="#173">173</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fileInfo</span><span class="default">-&gt;</span><span class="default">isFile</span><span class="keyword">(</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">&amp;&amp;</span><span class="default">&nbsp;</span><span class="default">$fileInfo</span><span class="default">-&gt;</span><span class="default">getExtension</span><span class="keyword">(</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">==</span><span class="default">&nbsp;</span><span class="default">'json'</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="174" href="#174">174</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Only&nbsp;delete&nbsp;files&nbsp;which&nbsp;we&nbsp;can&nbsp;lock.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 175" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="175" href="#175">175</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$successfullyDeleted</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">withLock</span><span class="keyword">(</span><span class="default">$fileInfo</span><span class="default">-&gt;</span><span class="default">getPathname</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">'r'</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">use</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fileInfo</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="176" href="#176">176</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Read&nbsp;the&nbsp;file,&nbsp;check&nbsp;expiry&nbsp;date!&nbsp;Only&nbsp;unlink&nbsp;if&nbsp;file&nbsp;is&nbsp;expired.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 177" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="177" href="#177">177</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$fileContents</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">''</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 178" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="178" href="#178">178</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$d</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">fread</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">1024</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="default">$fileContents</span><span class="default">&nbsp;</span><span class="default">.=</span><span class="default">&nbsp;</span><span class="default">$d</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="179" href="#179">179</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 180" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="180" href="#180">180</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$data</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">json_decode</span><span class="keyword">(</span><span class="default">$fileContents</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">true</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="181" href="#181">181</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 182" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="182" href="#182">182</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">!</span><span class="default">is_array</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="keyword">return</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="183" href="#183">183</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="184" href="#184">184</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;If&nbsp;valid_until&nbsp;is&nbsp;a&nbsp;valid&nbsp;time,&nbsp;and&nbsp;is&nbsp;in&nbsp;the&nbsp;past,&nbsp;delete&nbsp;the&nbsp;token.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 185" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="185" href="#185">185</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">is_int</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="default">??</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">&amp;&amp;</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">[</span><span class="default">'valid_until'</span><span class="keyword">]</span><span class="default">&nbsp;</span><span class="keyword">&lt;</span><span class="default">&nbsp;</span><span class="default">time</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 186" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="186" href="#186">186</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">unlink</span><span class="keyword">(</span><span class="default">$fileInfo</span><span class="default">-&gt;</span><span class="default">getPathname</span><span class="keyword">(</span><span class="keyword">)</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="187" href="#187">187</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 188" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="188" href="#188">188</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="189" href="#189">189</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 190" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="190" href="#190">190</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$successfullyDeleted</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span><span class="default">&nbsp;</span><span class="default">$deleted</span><span class="default">++</span><span class="keyword">;</span><span class="default">&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="191" href="#191">191</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="192" href="#192">192</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="193" href="#193">193</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 194" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="194" href="#194">194</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$deleted</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="195" href="#195">195</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="196" href="#196">196</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="197" href="#197">197</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">get</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$key</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="keyword">?</span><span class="keyword">array</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 198" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="198" href="#198">198</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$path</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">getPath</span><span class="keyword">(</span><span class="default">$key</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="199" href="#199">199</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 200" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="200" href="#200">200</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="keyword">!</span><span class="default">file_exists</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="3 tests cover line 201" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="201" href="#201">201</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="202" href="#202">202</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="203" href="#203">203</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 204" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="204" href="#204">204</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">withLock</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">'r'</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 205" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="205" href="#205">205</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$fileContents</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">''</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 206" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="206" href="#206">206</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">while</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$data</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">fread</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">1024</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 207" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="207" href="#207">207</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$fileContents</span><span class="default">&nbsp;</span><span class="default">.=</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="208" href="#208">208</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 209" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="209" href="#209">209</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$result</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">json_decode</span><span class="keyword">(</span><span class="default">$fileContents</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">true</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="210" href="#210">210</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 211" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="211" href="#211">211</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">is_array</span><span class="keyword">(</span><span class="default">$result</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 212" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="212" href="#212">212</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$result</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="213" href="#213">213</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="214" href="#214">214</a></td><td class="col-11 codeLine"></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="215" href="#215">215</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="4 tests cover line 216" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="216" href="#216">216</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="217" href="#217">217</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="218" href="#218">218</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="219" href="#219">219</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">put</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$key</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">array</span><span class="default">&nbsp;</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="default">bool</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="220" href="#220">220</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Ensure&nbsp;that&nbsp;the&nbsp;containing&nbsp;folder&nbsp;exists.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 221" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="221" href="#221">221</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">@</span><span class="default">mkdir</span><span class="keyword">(</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">0777</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">true</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="222" href="#222">222</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 223" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="223" href="#223">223</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">withLock</span><span class="keyword">(</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">getPath</span><span class="keyword">(</span><span class="default">$key</span><span class="keyword">)</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">'w'</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">use</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 224" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="224" href="#224">224</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">fwrite</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">json_encode</span><span class="keyword">(</span><span class="default">$data</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="default">!==</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 225" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="225" href="#225">225</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="226" href="#226">226</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="227" href="#227">227</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="228" href="#228">228</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">delete</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$key</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$observeLock</span><span class="keyword">=</span><span class="default">true</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="default">bool</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 229" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="229" href="#229">229</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$path</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">getPath</span><span class="keyword">(</span><span class="default">$key</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 230" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="230" href="#230">230</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">file_exists</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="5 tests cover line 231" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="231" href="#231">231</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$observeLock</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 232" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="232" href="#232">232</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">withLock</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">'r'</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">use</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 233" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="233" href="#233">233</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">unlink</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="2 tests cover line 234" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="234" href="#234">234</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="235" href="#235">235</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="default">&nbsp;</span><span class="keyword">else</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="3 tests cover line 236" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="236" href="#236">236</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">unlink</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="237" href="#237">237</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="238" href="#238">238</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="239" href="#239">239</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="240" href="#240">240</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="241" href="#241">241</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="242" href="#242">242</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">getPath</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$key</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="default">string</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="243" href="#243">243</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;TODO:&nbsp;ensure&nbsp;that&nbsp;the&nbsp;calculated&nbsp;path&nbsp;is&nbsp;a&nbsp;child&nbsp;of&nbsp;$this-&gt;path.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 244" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="244" href="#244">244</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">path</span><span class="default">&nbsp;</span><span class="keyword">.</span><span class="default">&nbsp;</span><span class="string">&quot;</span><span class="string">$key</span><span class="string">.json</span><span class="string">&quot;</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="245" href="#245">245</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="246" href="#246">246</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="247" href="#247">247</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">withLock</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$mode</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="keyword">callable</span><span class="default">&nbsp;</span><span class="default">$callback</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 248" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="248" href="#248">248</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$fp</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="keyword">@</span><span class="default">fopen</span><span class="keyword">(</span><span class="default">$path</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$mode</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="249" href="#249">249</a></td><td class="col-11 codeLine"></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 250" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="250" href="#250">250</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">$fp</span><span class="default">&nbsp;</span><span class="default">===</span><span class="default">&nbsp;</span><span class="default">false</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="1 test covers line 251" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="251" href="#251">251</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="252" href="#252">252</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="253" href="#253">253</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="254" href="#254">254</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Wait&nbsp;for&nbsp;a&nbsp;lock.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 255" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="255" href="#255">255</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">if</span><span class="default">&nbsp;</span><span class="keyword">(</span><span class="default">flock</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">LOCK_EX</span><span class="keyword">)</span><span class="keyword">)</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 256" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="256" href="#256">256</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$return</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="257" href="#257">257</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="258" href="#258">258</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Perform&nbsp;whatever&nbsp;action&nbsp;on&nbsp;the&nbsp;file&nbsp;pointer.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 259" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="259" href="#259">259</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">$return</span><span class="default">&nbsp;</span><span class="keyword">=</span><span class="default">&nbsp;</span><span class="default">$callback</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 260" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="260" href="#260">260</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span><span class="default">&nbsp;</span><span class="keyword">finally</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="261" href="#261">261</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;Regardless&nbsp;of&nbsp;what&nbsp;happens,&nbsp;release&nbsp;the&nbsp;lock.</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 262" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="262" href="#262">262</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">flock</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">LOCK_UN</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 263" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="263" href="#263">263</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="default">fclose</span><span class="keyword">(</span><span class="default">$fp</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="264" href="#264">264</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="8 tests cover line 265" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCrud&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\FilesystemJsonStorageTest::testCleanUp&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="265" href="#265">265</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">$return</span><span class="keyword">;</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="266" href="#266">266</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="267" href="#267">267</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&nbsp;It&nbsp;wasnt&nbsp;possible&nbsp;to&nbsp;get&nbsp;a&nbsp;lock.</span></td></tr>
<tr class="danger d-flex"><td class="col-1 text-right"><a id="268" href="#268">268</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">null</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="269" href="#269">269</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="270" href="#270">270</a></td><td class="col-11 codeLine"></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="271" href="#271">271</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">protected</span><span class="default">&nbsp;</span><span class="keyword">function</span><span class="default">&nbsp;</span><span class="default">hash</span><span class="keyword">(</span><span class="default">string</span><span class="default">&nbsp;</span><span class="default">$token</span><span class="keyword">)</span><span class="keyword">:</span><span class="default">&nbsp;</span><span class="default">string</span><span class="default">&nbsp;</span><span class="keyword">{</span></td></tr>
<tr class="covered-by-large-tests popin d-flex"><td data-title="6 tests cover line 272" data-content="&lt;ul&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testValidApprovalRequestIsHandledCorrectly&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testExchangeFlowsReturnErrorOnInvalidParameters&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeFailsForTokensWithInvalidScope&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testAuthEndpointTokenExchangeReturnsCorrectResponseForValidRequest&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsErrorIfAccessCodeGrantsNoScopes&lt;/li&gt;&lt;li class=&quot;covered-by-large-tests&quot;&gt;Taproot\IndieAuth\Test\ServerTest::testTokenEndpointReturnsAccessTokenOnValidRequest&lt;/li&gt;&lt;/ul&gt;" data-placement="top" data-html="true" class="col-1 text-right"><a id="272" href="#272">272</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span class="default">&nbsp;</span><span class="default">hash_hmac</span><span class="keyword">(</span><span class="default">'sha256'</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$token</span><span class="keyword">,</span><span class="default">&nbsp;</span><span class="default">$this</span><span class="default">-&gt;</span><span class="default">secret</span><span class="keyword">)</span><span class="keyword">;</span></td></tr>
<tr class="warning d-flex"><td class="col-1 text-right"><a id="273" href="#273">273</a></td><td class="col-11 codeLine"><span class="default">&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">}</span></td></tr>
<tr class=" d-flex"><td class="col-1 text-right"><a id="274" href="#274">274</a></td><td class="col-11 codeLine"><span class="keyword">}</span></td></tr>
</tbody>
</table>
<footer>
<hr/>
<h4>Legend</h4>
<p><span class="success"><strong>Executed</strong></span><span class="danger"><strong>Not Executed</strong></span><span class="warning"><strong>Dead Code</strong></span></p>
<p>
<small>Generated by <a href="https://github.com/sebastianbergmann/php-code-coverage" target="_top">php-code-coverage 9.2.6</a> using <a href="https://secure.php.net/" target="_top">PHP 7.4.19</a> with <a href="https://xdebug.org/">Xdebug 3.0.4</a> and <a href="https://phpunit.de/">PHPUnit 9.5.5</a> at Sun Jun 13 13:34:45 UTC 2021.</small>
</p>
<a title="Back to the top" id="toplink" href="#">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="16" viewBox="0 0 12 16"><path fill-rule="evenodd" d="M12 11L6 5l-6 6h12z"/></svg>
</a>
</footer>
</div>
<script src="../_js/jquery.min.js" type="text/javascript"></script>
<script src="../_js/popper.min.js" type="text/javascript"></script>
<script src="../_js/bootstrap.min.js" type="text/javascript"></script>
<script src="../_js/file.js" type="text/javascript"></script>
</body>
</html>