feat: add signup, login, session, and create_user

signup calls POST /auth/signup and leaves the stored JWT in place.
login writes the VeraeTime token to the auth properties file and
does not return it. A stored username and password refresh that
token when expires_at is missing or within five minutes.
create_user still requires an admin session.
This commit is contained in:
George Lambert 2026-09-23 11:15:11 -04:00
commit c547804835
3 changed files with 730 additions and 31 deletions

View file

@ -201,6 +201,104 @@ when the stored scope ranks lower</td>
</table>
<p>Returns <code>{ "receipts": [ ... ] }</code> from the local file.
Global-only certificates are not listed.</p>
<h2 id="login">login</h2>
<table>
<thead>
<tr>
<th>Argument</th>
<th>Default</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>username</code></td>
<td>required</td>
<td>VeraeTime account</td>
</tr>
<tr>
<td><code>password</code></td>
<td>required</td>
<td>VeraeTime password</td>
</tr>
</tbody>
</table>
<p><code>POST /auth/login</code>. Stores <code>access_token</code>,
<code>id_token</code>, <code>auth_token</code>, <code>expires_at</code>,
<code>username</code>, and <code>password</code> in the auth properties
file (mode <code>0600</code>) and replaces the in-memory JWT. Returns
<code>username</code>, <code>role</code>, and <code>expires_at</code>.
The JWT is not returned.</p>
<h2 id="session">session</h2>
<p>No arguments. <code>GET /auth/validate</code> with the stored
JWT.</p>
<p>Returns <code>valid</code>, <code>username</code>, <code>role</code>,
and <code>expires_at</code>.</p>
<h2 id="signup">signup</h2>
<table>
<thead>
<tr>
<th>Argument</th>
<th>Default</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>username</code></td>
<td>required</td>
<td>New account</td>
</tr>
<tr>
<td><code>password</code></td>
<td>required</td>
<td>New password</td>
</tr>
</tbody>
</table>
<p><code>POST /auth/signup</code> with no bearer token. The timestamping
service creates the account with role <code>user</code>. Returns
<code>id</code>, <code>username</code>, and <code>role</code>. Does not
replace the JWT stored for <code>stamp</code>. A new account calls
<code>login</code> to become the stored session.
<code>create_user</code> remains the admin path and can set
<code>admin</code>.</p>
<h2 id="create_user">create_user</h2>
<table>
<thead>
<tr>
<th>Argument</th>
<th>Default</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>username</code></td>
<td>required</td>
<td>New account</td>
</tr>
<tr>
<td><code>password</code></td>
<td>required</td>
<td>New password</td>
</tr>
<tr>
<td><code>role</code></td>
<td>required</td>
<td><code>user</code> or <code>admin</code></td>
</tr>
</tbody>
</table>
<p><code>POST /auth/users</code> with the stored JWT. Refuses unless
<code>session</code> reports role <code>admin</code>. Returns
<code>id</code>, <code>username</code>, and <code>role</code>. There is
no public signup; the first admin already exists on the timestamping
service.</p>
<p>A stored login is refreshed when <code>stamp</code> or
<code>verify</code> runs and <code>expires_at</code> is missing or
within 5 minutes, if <code>username</code> and <code>password</code> are
in the auth file.</p>
<h2 id="environment">Environment</h2>
<table>
<thead>

View file

@ -112,9 +112,14 @@
<code>site/index.html</code> on the same machine, or put TLS and an
access control in front of a non-loopback bind you choose yourself.</p>
<h2 id="global-token">Global token</h2>
<div class="sourceCode" id="cb5"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># POST https://api.veraetime.net/auth/login and store access_token=</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="co"># in ~/.verae/auth.properties (mode 600), or:</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">VERAE_GLOBAL_TOKEN</span><span class="op">=</span>...</span></code></pre></div>
<p><code>signup</code> creates a role <code>user</code> account with no
bearer token. Call <code>login</code> with that username and password to
store the JWT in <code>~/.verae/auth.properties</code> (mode 600). The
server uses it for <code>scope=global</code> without a restart.
<code>session</code> checks that JWT. <code>create_user</code> adds an
account when the stored role is <code>admin</code>.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># or skip the tool and export a token yourself:</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="bu">export</span> <span class="va">VERAE_GLOBAL_TOKEN</span><span class="op">=</span>...</span></code></pre></div>
<h2 id="tests">Tests</h2>
<div class="sourceCode" id="cb6"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">uv</span> run pytest</span></code></pre></div>
<p>Stamp traces (live VeraeTime) are a separate script. They write

View file

@ -90,6 +90,17 @@ means “not in the local file,” not “VeraeTime has no record.”</p>
<code>access_token</code> / <code>id_token</code> /
<code>auth_token</code> in <code>~/.verae/auth.properties</code>
(<code>VERAE_AUTH_PROPERTIES</code> overrides the path).</li>
<li><code>login</code> writes that file (mode <code>0600</code>),
including <code>username</code>, <code>password</code>, and
<code>expires_at</code>. The tool result does not include the JWT.</li>
<li><code>signup</code> calls <code>POST /auth/signup</code> with no
bearer token. The account role is <code>user</code>. It does not replace
the stored JWT.</li>
<li><code>create_user</code> calls <code>POST /auth/users</code> only
when the stored token’s role is <code>admin</code>.</li>
<li>Before a global stamp or verify, a stored username and password are
used to log in again when <code>expires_at</code> is missing or within 5
minutes.</li>
<li>Do not commit tokens. <code>.env</code> is gitignored.</li>
<li>The local receipt file is mode <code>0600</code> after each
save.</li>