mikser-io-auth 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/lib/tokens.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -227,6 +227,44 @@ keeps them: a registered client and its refresh token exist only because a
|
|
|
227
227
|
human completed a sign-in once, and they are not something the working folder
|
|
228
228
|
can rebuild.
|
|
229
229
|
|
|
230
|
+
### Minted tokens
|
|
231
|
+
|
|
232
|
+
`auth()` publishes a minting surface at `runtime.options.auth`, so another
|
|
233
|
+
plugin can hand out a credential **narrower than the caller's own** without
|
|
234
|
+
importing this package:
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
runtime.options.auth.mint({
|
|
238
|
+
subject: principal.subject,
|
|
239
|
+
capabilities: principal.capabilities, // what they already hold
|
|
240
|
+
request: ['webdav:media', 'webdav:media:write'],
|
|
241
|
+
ttlSec: 300,
|
|
242
|
+
purpose: 'webdav:media (write)',
|
|
243
|
+
})
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The scopes are the **intersection** of `request` and `capabilities`. This can
|
|
247
|
+
only ever narrow: there is no argument that widens anyone's reach, and asking
|
|
248
|
+
for a scope the caller does not hold is refused with the missing one named
|
|
249
|
+
rather than trimmed silently. A caller whose `capabilities` are `null` — a
|
|
250
|
+
static token, not capability-scoped — is refused outright, because it cannot
|
|
251
|
+
delegate what it cannot enumerate.
|
|
252
|
+
|
|
253
|
+
A minted token carries a **`jti`** and is recorded in `mikser_auth_minted`, which
|
|
254
|
+
makes it revokable before it expires — the one thing an ordinary JWT is not, and
|
|
255
|
+
the thing that matters for a credential handed to a machine that logs its own
|
|
256
|
+
output. `revokeMinted(jti)` kills one; `listMinted(subject)` is the audit view.
|
|
257
|
+
Every mint is logged with subject, purpose, scopes and ttl.
|
|
258
|
+
|
|
259
|
+
Verification **fails closed**: a token with a `jti` whose row is missing, or
|
|
260
|
+
whose checker was never wired, is rejected. Losing the record must revoke, never
|
|
261
|
+
un-revoke. Session tokens carry no `jti`, so they never touch this table and
|
|
262
|
+
gain no new failure mode.
|
|
263
|
+
|
|
264
|
+
Minted tokens are **not refreshable**. Expiry is the revocation mechanism, so
|
|
265
|
+
they are deliberately short and a caller mints again rather than renewing one
|
|
266
|
+
that has been sitting in a transcript.
|
|
267
|
+
|
|
230
268
|
### When an access token expires
|
|
231
269
|
|
|
232
270
|
Access tokens are short (`ttl`, default `1h`) and refresh tokens are long, so
|
package/lib/tokens.js
CHANGED
|
@@ -13,7 +13,7 @@ export async function issueToken({ key, issuer, audience, subject, capabilities
|
|
|
13
13
|
// list, and a client library will parse it as one. The row filter travels
|
|
14
14
|
// as a private claim so the two never collide. It is signed, so a client
|
|
15
15
|
// cannot widen its own reach by editing it.
|
|
16
|
-
|
|
16
|
+
const signer = new SignJWT({
|
|
17
17
|
scope: capabilities.join(' '),
|
|
18
18
|
...(scope ? { mks_scope: scope } : {}),
|
|
19
19
|
})
|
|
@@ -23,7 +23,7 @@ export async function issueToken({ key, issuer, audience, subject, capabilities
|
|
|
23
23
|
.setAudience(audience)
|
|
24
24
|
.setSubject(subject)
|
|
25
25
|
.setExpirationTime(ttl)
|
|
26
|
-
|
|
26
|
+
return signer.sign(key.privateKey)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// Verify a token minted by this server. `audience` is checked because a
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikser-io-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Authentication for mikser-io: an OAuth 2.1 authorization server (self-registering clients, authorization code + PKCE, refresh rotation) and HTTP Basic / JWT verifiers over Apache-format htpasswd and htgroup files in the working folder. Implements the ADR-0012 verifier contract, so it plugs in wherever a static token does — api, mcp, forms.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|