@hyper.authio/server 0.1.1 → 0.7.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 +37 -7
- package/dist/index.cjs +270 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -16
- package/dist/index.d.ts +165 -16
- package/dist/index.js +267 -98
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -30,8 +30,12 @@ try {
|
|
|
30
30
|
|
|
31
31
|
| Option | Default | |
|
|
32
32
|
| --- | --- | --- |
|
|
33
|
-
| `audiences` | | Required. |
|
|
34
|
-
| `
|
|
33
|
+
| `audiences` | | Required, unless `resource` is set. |
|
|
34
|
+
| `resource` | | The API's own resource identifier (RFC 8707); added to `audiences` and used for RFC 9728. |
|
|
35
|
+
| `resourceMetadata` | off | `true` (or the URL) adds `resource_metadata="{origin}/.well-known/oauth-protected-resource{path}"` to `401` challenges (RFC 9728). |
|
|
36
|
+
| `requiredScopes` | | Scopes every request must carry (all); `authioBearer` answers `403 insufficient_scope`. |
|
|
37
|
+
| `clientEncryptionKey`, `clientEncryptionKeyPath` | | Decrypts access tokens Authio encrypts to this key (RSA-OAEP, RSA-OAEP-256) and validates them locally. RSA1_5 is refused (`legacy_algorithm`), even with `allowLegacyEncryptionAlgorithms`. |
|
|
38
|
+
| `introspection` | `none` | `none`: local JWT validation. `activeCheck`: then confirmed active by introspection (cached per `jti`), so a revoked token, an ended session or a suspension is refused before the token expires. `introspectionOnly`: introspection alone, for opaque tokens (or encrypted ones without the key). |
|
|
35
39
|
| `client` | | The API's confidential client, needed by introspection: an `AuthioClient` or `{ clientId, clientSecret }` (or a private key). It must be the resource server's introspection client. |
|
|
36
40
|
| `introspectionCacheDuration` | 30 s | Never past the token's expiry; only active answers are kept. |
|
|
37
41
|
| `clockSkew` | 30 s | |
|
|
@@ -41,8 +45,20 @@ try {
|
|
|
41
45
|
| `groupClaims` | `["groups"]` | Claims holding group names (a Group claim mapper). |
|
|
42
46
|
|
|
43
47
|
A refusal is an `AuthioBearerError` whose `wwwAuthenticate` is `Bearer` when the request had no token, and
|
|
44
|
-
`Bearer error="invalid_token", error_description="…"` otherwise
|
|
45
|
-
|
|
48
|
+
`Bearer error="invalid_token", error_description="…"` otherwise (plus `resource_metadata` when turned on). Its
|
|
49
|
+
`reason` names why, with the outcome names of `conformance/tokens.json` (`expired`, `invalid_audience`,
|
|
50
|
+
`not_access_token`, `reference_token`, `decryption_failed`, …, and `inactive` / `unconfirmed` for introspection). A
|
|
51
|
+
token addressed elsewhere is described with the audience the API accepts; introspection failures fail closed.
|
|
52
|
+
|
|
53
|
+
### Protected resource metadata (RFC 9728)
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { createProtectedResourceMetadata, protectedResourceMetadataPath } from "@hyper.authio/server";
|
|
57
|
+
|
|
58
|
+
const verifier = createAuthioVerifier({ issuer, resource: "https://orders.example.com/api", resourceMetadata: true });
|
|
59
|
+
const path = protectedResourceMetadataPath(verifier.resource!); // /.well-known/oauth-protected-resource/api
|
|
60
|
+
const document = createProtectedResourceMetadata({ issuer, resource: verifier.resource!, scopesSupported: ["orders:read"] });
|
|
61
|
+
```
|
|
46
62
|
|
|
47
63
|
## The caller
|
|
48
64
|
|
|
@@ -50,6 +66,13 @@ audience the API accepts; introspection failures fail closed.
|
|
|
50
66
|
|
|
51
67
|
```ts
|
|
52
68
|
user.subject; user.clientId; user.scopes;
|
|
69
|
+
user.kind; // "user" | "client" | "consumer" | "account_credential"
|
|
70
|
+
user.credentialForm; // "client_secret" | "personal_access_token" | "api_key" | "consumer_api_key" (machines only)
|
|
71
|
+
user.consumerName; user.credentialId; user.credentialName; user.ownerUserId; user.ownerUsername; user.accountId;
|
|
72
|
+
user.credentialRealm; user.credentialClient; // what an account credential is limited to
|
|
73
|
+
user.impersonated; user.impersonator; // an administrator acting as the person (act.sub)
|
|
74
|
+
user.delegated; user.delegationId; user.actorChain; // clients acting for the person (act.client_id), outermost first
|
|
75
|
+
user.authTime; // auth_time, in seconds
|
|
53
76
|
user.roles; // *_resource_access roles, then flat role claims
|
|
54
77
|
user.permissions; // { orders: ["read", "write"] }
|
|
55
78
|
user.resourceAccess; // per-source entries: user, realm, client, plan, consumer, secret, system
|
|
@@ -64,7 +87,8 @@ user.hasGroup("finance");
|
|
|
64
87
|
user.hasClaim("department", "finance", "sales");
|
|
65
88
|
```
|
|
66
89
|
|
|
67
|
-
The raw token is kept as `user.token`, not enumerable, so it stays out of logs and JSON.
|
|
90
|
+
The raw token is kept as `user.token`, not enumerable, so it stays out of logs and JSON. The caller fields follow
|
|
91
|
+
`conformance/callers.json`; `AuthioUser.fromIntrospection(answer)` reads an introspection answer the same way.
|
|
68
92
|
|
|
69
93
|
## Authorize
|
|
70
94
|
|
|
@@ -81,8 +105,14 @@ if (refusal) {
|
|
|
81
105
|
```
|
|
82
106
|
|
|
83
107
|
Rules: `requireScope`, `requireRole`, `requirePermission`, `requireGroup`, `requireClaim`, `requireOrganization`,
|
|
84
|
-
`requireAuthenticationLevel`, `requireAuthenticationMethod`, `
|
|
85
|
-
`authorize` checks every rule and joins their messages.
|
|
108
|
+
`requireAuthenticationLevel`, `requireAuthenticationMethod`, `requireRecentAuthentication`, `requireCallerKind`,
|
|
109
|
+
`requireClient`, combined with `allOf` and `anyOf`. `authorize` checks every rule and joins their messages.
|
|
110
|
+
|
|
111
|
+
**Step-up (RFC 9470)**: `requireAuthenticationLevel(2, { maxAge: 300 })`, `requireAuthenticationMethod("otp")` and
|
|
112
|
+
`requireRecentAuthentication(300)` refuse with `insufficient_user_authentication`, `acrValues` (the level asked for;
|
|
113
|
+
`2` for `mfa`/`otp`/`mca`, `3` for `swk`/`hwk`) and `maxAge`, so the challenge reads
|
|
114
|
+
`Bearer error="insufficient_user_authentication", error_description="…", acr_values="2", max_age=300`. A client
|
|
115
|
+
answers it with `createStepUpAuthorizationUrl` from `@hyper.authio/client`.
|
|
86
116
|
|
|
87
117
|
## Webhooks
|
|
88
118
|
|