@toa.io/extensions.exposition 1.0.0-alpha.250 → 1.0.0-alpha.252
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/components/identity.bans/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/manifest.toa.yaml +16 -0
- package/components/identity.basic/operations/delete.d.ts +7 -0
- package/components/identity.basic/operations/delete.js +11 -0
- package/components/identity.basic/operations/delete.js.map +1 -0
- package/components/identity.basic/operations/info.d.ts +10 -0
- package/components/identity.basic/operations/info.js +11 -0
- package/components/identity.basic/operations/info.js.map +1 -0
- package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.basic/operations/types.d.ts +2 -1
- package/components/identity.basic/source/delete.ts +15 -0
- package/components/identity.basic/source/info.ts +19 -0
- package/components/identity.basic/source/types.ts +2 -1
- package/components/identity.credentials/manifest.toa.yaml +57 -0
- package/components/identity.credentials/operations/list.d.ts +51 -0
- package/components/identity.credentials/operations/list.js +32 -0
- package/components/identity.credentials/operations/list.js.map +1 -0
- package/components/identity.credentials/operations/tsconfig.tsbuildinfo +1 -0
- package/components/identity.credentials/source/list.test.ts +47 -0
- package/components/identity.credentials/source/list.ts +87 -0
- package/components/identity.credentials/tsconfig.json +7 -0
- package/components/identity.federation/manifest.toa.yaml +35 -1
- package/components/identity.federation/operations/authenticate.js +1 -1
- package/components/identity.federation/operations/authenticate.js.map +1 -1
- package/components/identity.federation/operations/delete.d.ts +8 -0
- package/components/identity.federation/operations/delete.js +11 -0
- package/components/identity.federation/operations/delete.js.map +1 -0
- package/components/identity.federation/operations/incept.js +14 -4
- package/components/identity.federation/operations/incept.js.map +1 -1
- package/components/identity.federation/operations/list.d.ts +7 -0
- package/components/identity.federation/operations/list.js +18 -0
- package/components/identity.federation/operations/list.js.map +1 -0
- package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.federation/operations/types/context.d.ts +5 -5
- package/components/identity.federation/operations/types/entity.d.ts +2 -0
- package/components/identity.federation/source/authenticate.ts +1 -1
- package/components/identity.federation/source/delete.ts +16 -0
- package/components/identity.federation/source/incept.ts +18 -4
- package/components/identity.federation/source/list.test.ts +23 -0
- package/components/identity.federation/source/list.ts +23 -0
- package/components/identity.federation/source/types/context.ts +5 -6
- package/components/identity.federation/source/types/entity.ts +2 -0
- package/components/identity.keys/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.otp/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.passkeys/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
- package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
- package/documentation/components.md +3 -0
- package/documentation/credentials.md +85 -0
- package/documentation/identity.md +3 -0
- package/documentation/passkeys.md +1 -0
- package/features/credentials.feature +106 -0
- package/features/steps/Database.ts +6 -2
- package/package.json +6 -5
- package/transpiled/tsconfig.tsbuildinfo +1 -1
|
@@ -5,6 +5,9 @@ configured in the same
|
|
|
5
5
|
way as if they were a part of the Context. Resources exposed by the components
|
|
6
6
|
are [isolated](tree.md#directives).
|
|
7
7
|
|
|
8
|
+
See [Persistent credentials](credentials.md) for the centralized Basic, federation, and passkey
|
|
9
|
+
management API.
|
|
10
|
+
|
|
8
11
|
## Basic credentials
|
|
9
12
|
|
|
10
13
|
The `identity.basic` component stores basic credentials.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Persistent credentials
|
|
2
|
+
|
|
3
|
+
Persistent credentials associate an [Identity](identity.md) with a reusable authentication method.
|
|
4
|
+
Exposition stores Basic, OpenID Connect federation, and WebAuthn passkey credentials. Local tokens
|
|
5
|
+
and one-time passwords are not persistent credentials: tokens are stateless and OTP records expire.
|
|
6
|
+
|
|
7
|
+
See [Features](../features/credentials.feature).
|
|
8
|
+
|
|
9
|
+
## Listing credentials
|
|
10
|
+
|
|
11
|
+
`GET /identity/credentials/:identity/` returns all persistent credentials associated with the
|
|
12
|
+
Identity in the current authority. Access requires credentials of that Identity.
|
|
13
|
+
|
|
14
|
+
```http
|
|
15
|
+
GET /identity/credentials/fc8e66ddd51d45eea89602c9dd38a542/ HTTP/1.1
|
|
16
|
+
authorization: Token ...
|
|
17
|
+
accept: application/yaml
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```yaml
|
|
21
|
+
basic:
|
|
22
|
+
username: user@example.com
|
|
23
|
+
federation:
|
|
24
|
+
- id: 09200d0bcc2448c5863e3f50ae18af84
|
|
25
|
+
iss: https://accounts.google.com
|
|
26
|
+
_created: 1754899200000
|
|
27
|
+
passkeys:
|
|
28
|
+
- id: 54ed430804324e81b39756ea4708b546
|
|
29
|
+
aid: adce0002-35bc-c60a-648b-0b25f1f05503
|
|
30
|
+
synced: true
|
|
31
|
+
label: Personal iPhone
|
|
32
|
+
_created: 1754899200000
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`basic` is `null` when Basic credentials do not exist. `federation` and `passkeys` are always
|
|
36
|
+
arrays. Secret and authentication data, including password hashes, federation subjects, public
|
|
37
|
+
keys, signature counters, and transports, are not returned.
|
|
38
|
+
|
|
39
|
+
The federation issuer identifies the provider. For example, Google uses
|
|
40
|
+
`https://accounts.google.com` and Apple uses `https://appleid.apple.com`. Applications should map
|
|
41
|
+
trusted issuers to their own provider names and presentation.
|
|
42
|
+
|
|
43
|
+
The passkey `aid` is its
|
|
44
|
+
[AAGUID](https://www.w3.org/TR/webauthn-2/#aaguid), which can be resolved against an authenticator
|
|
45
|
+
metadata catalog. `synced` indicates whether the credential was backed up and is therefore likely
|
|
46
|
+
available on more than one device.
|
|
47
|
+
|
|
48
|
+
## Basic credentials
|
|
49
|
+
|
|
50
|
+
- `POST /identity/basic/:identity/` adds Basic credentials to an Identity.
|
|
51
|
+
- `PATCH /identity/basic/:identity/` changes its username or password.
|
|
52
|
+
- `DELETE /identity/basic/:identity/` removes its Basic credentials.
|
|
53
|
+
|
|
54
|
+
An Identity can have at most one Basic credential in an authority. See
|
|
55
|
+
[Basic credentials configuration](components.md#basic-credentials) for password hashing,
|
|
56
|
+
constraints, and principal configuration.
|
|
57
|
+
|
|
58
|
+
## Federation credentials
|
|
59
|
+
|
|
60
|
+
- `POST /identity/federation/:identity/` associates credentials from a trusted issuer.
|
|
61
|
+
- `GET /identity/federation/:identity/` lists federation credentials.
|
|
62
|
+
- `DELETE /identity/federation/:identity/:credential/` removes one federation credential.
|
|
63
|
+
|
|
64
|
+
An Identity can have credentials from multiple issuers and can have multiple subjects from the
|
|
65
|
+
same issuer. The `:credential` segment is the `id` returned by either listing resource. Federation
|
|
66
|
+
resources are provider-independent; issuer-specific authorization flows remain the responsibility
|
|
67
|
+
of the application.
|
|
68
|
+
|
|
69
|
+
## Passkeys
|
|
70
|
+
|
|
71
|
+
Passkey registration consists of a challenge followed by credential creation:
|
|
72
|
+
|
|
73
|
+
- `POST /identity/passkeys/challenges/:identity/` creates a registration challenge.
|
|
74
|
+
- `POST /identity/passkeys/:identity/` verifies the response and stores the passkey.
|
|
75
|
+
- `GET /identity/passkeys/:identity/` lists passkeys.
|
|
76
|
+
- `DELETE /identity/passkeys/:identity/:credential/` removes one passkey.
|
|
77
|
+
|
|
78
|
+
See [Web Authentication](passkeys.md) for standards and feature scenarios.
|
|
79
|
+
|
|
80
|
+
## Removing the last credential
|
|
81
|
+
|
|
82
|
+
Credential components intentionally do not coordinate with one another. Consequently, credentials
|
|
83
|
+
can be removed without checking whether another persistent credential exists.
|
|
84
|
+
Applications that require a recoverable login must prevent removal of the last usable credential
|
|
85
|
+
in their client workflow.
|
|
@@ -6,6 +6,9 @@ identifier** of an individual, organization, application or device.
|
|
|
6
6
|
To prove its Identity, the request originator must provide a valid _credentials_ that are associated
|
|
7
7
|
with that Identity.
|
|
8
8
|
|
|
9
|
+
Persistent authentication methods and their management resources are described in
|
|
10
|
+
[Persistent credentials](credentials.md).
|
|
11
|
+
|
|
9
12
|
Identity is intrinsically linked to credentials, as an Identity is established only when the first
|
|
10
13
|
set of credentials for that Identity is created.
|
|
11
14
|
In other words, the creation of credentials marks the inception of an Identity.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
@security
|
|
2
|
+
Feature: Persistent credentials management
|
|
3
|
+
|
|
4
|
+
Background:
|
|
5
|
+
# developer:secret
|
|
6
|
+
Given the `identity.basic` database contains:
|
|
7
|
+
| _id | authority | username | password |
|
|
8
|
+
| efe3a65ebbee47ed95a73edd911ea328 | nex | developer | $2b$10$ZRSKkgZoGnrcTNA5w5eCcu3pxDzdTduhteVYXcp56AaNcilNkwJ.O |
|
|
9
|
+
And the `identity.federation` database contains:
|
|
10
|
+
| _id | authority | identity | iss | sub | _created |
|
|
11
|
+
| fed3a65ebbee47ed95a73edd911ea328 | nex | efe3a65ebbee47ed95a73edd911ea328 | https://accounts.google.com | google | 1000 |
|
|
12
|
+
| fed3a65ebbee47ed95a73edd911ea329 | nex | efe3a65ebbee47ed95a73edd911ea328 | https://appleid.apple.com | apple | 900 |
|
|
13
|
+
And the `identity.passkeys` database contains:
|
|
14
|
+
| _id | authority | identity | kid | aid | synced | key | counter | label | _created |
|
|
15
|
+
| ace3a65ebbee47ed95a73edd911ea328 | nex | efe3a65ebbee47ed95a73edd911ea328 | key-one | adce0002-35bc-c60a-648b-0b25f1f05503 | true | cHVibGlj | 0 | Personal iPhone | 2000 |
|
|
16
|
+
|
|
17
|
+
Scenario: Listing all persistent credentials
|
|
18
|
+
When the following request is received:
|
|
19
|
+
"""
|
|
20
|
+
GET /identity/credentials/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
21
|
+
host: nex.toa.io
|
|
22
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
23
|
+
accept: application/yaml
|
|
24
|
+
"""
|
|
25
|
+
Then the following reply is sent:
|
|
26
|
+
"""
|
|
27
|
+
200 OK
|
|
28
|
+
authorization: Token ${{ token }}
|
|
29
|
+
|
|
30
|
+
basic:
|
|
31
|
+
username: developer
|
|
32
|
+
federation:
|
|
33
|
+
- id: fed3a65ebbee47ed95a73edd911ea328
|
|
34
|
+
iss: https://accounts.google.com
|
|
35
|
+
_created: 1000
|
|
36
|
+
- id: fed3a65ebbee47ed95a73edd911ea329
|
|
37
|
+
iss: https://appleid.apple.com
|
|
38
|
+
_created: 900
|
|
39
|
+
passkeys:
|
|
40
|
+
- id: ace3a65ebbee47ed95a73edd911ea328
|
|
41
|
+
aid: adce0002-35bc-c60a-648b-0b25f1f05503
|
|
42
|
+
synced: true
|
|
43
|
+
label: Personal iPhone
|
|
44
|
+
_created: 2000
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
Scenario: Deleting credentials through their components
|
|
48
|
+
When the following request is received:
|
|
49
|
+
"""
|
|
50
|
+
GET /identity/credentials/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
51
|
+
host: nex.toa.io
|
|
52
|
+
authorization: Basic ZGV2ZWxvcGVyOnNlY3JldA==
|
|
53
|
+
"""
|
|
54
|
+
Then the following reply is sent:
|
|
55
|
+
"""
|
|
56
|
+
200 OK
|
|
57
|
+
authorization: Token ${{ token }}
|
|
58
|
+
"""
|
|
59
|
+
When the following request is received:
|
|
60
|
+
"""
|
|
61
|
+
DELETE /identity/basic/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
62
|
+
host: nex.toa.io
|
|
63
|
+
authorization: Token ${{ token }}
|
|
64
|
+
"""
|
|
65
|
+
Then the following reply is sent:
|
|
66
|
+
"""
|
|
67
|
+
204 No Content
|
|
68
|
+
"""
|
|
69
|
+
When the following request is received:
|
|
70
|
+
"""
|
|
71
|
+
DELETE /identity/federation/efe3a65ebbee47ed95a73edd911ea328/fed3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
72
|
+
host: nex.toa.io
|
|
73
|
+
authorization: Token ${{ token }}
|
|
74
|
+
"""
|
|
75
|
+
Then the following reply is sent:
|
|
76
|
+
"""
|
|
77
|
+
204 No Content
|
|
78
|
+
"""
|
|
79
|
+
When the following request is received:
|
|
80
|
+
"""
|
|
81
|
+
DELETE /identity/passkeys/efe3a65ebbee47ed95a73edd911ea328/ace3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
82
|
+
host: nex.toa.io
|
|
83
|
+
authorization: Token ${{ token }}
|
|
84
|
+
"""
|
|
85
|
+
Then the following reply is sent:
|
|
86
|
+
"""
|
|
87
|
+
204 No Content
|
|
88
|
+
"""
|
|
89
|
+
When the following request is received:
|
|
90
|
+
"""
|
|
91
|
+
GET /identity/credentials/efe3a65ebbee47ed95a73edd911ea328/ HTTP/1.1
|
|
92
|
+
host: nex.toa.io
|
|
93
|
+
authorization: Token ${{ token }}
|
|
94
|
+
accept: application/yaml
|
|
95
|
+
"""
|
|
96
|
+
Then the following reply is sent:
|
|
97
|
+
"""
|
|
98
|
+
200 OK
|
|
99
|
+
|
|
100
|
+
basic: null
|
|
101
|
+
federation:
|
|
102
|
+
- id: fed3a65ebbee47ed95a73edd911ea329
|
|
103
|
+
iss: https://appleid.apple.com
|
|
104
|
+
_created: 900
|
|
105
|
+
passkeys: []
|
|
106
|
+
"""
|
|
@@ -25,7 +25,11 @@ export class Database {
|
|
|
25
25
|
? int
|
|
26
26
|
: str === 'null'
|
|
27
27
|
? null
|
|
28
|
-
: str
|
|
28
|
+
: str === 'true'
|
|
29
|
+
? true
|
|
30
|
+
: str === 'false'
|
|
31
|
+
? false
|
|
32
|
+
: str
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
documents.push(document)
|
|
@@ -62,4 +66,4 @@ export class Database {
|
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
type Document = Record<string, string | number | null>
|
|
69
|
+
type Document = Record<string, string | number | boolean | null>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/extensions.exposition",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.252",
|
|
4
4
|
"description": "Toa Exposition",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"@aws-sdk/protocol-http": "3.370.0",
|
|
21
21
|
"@simplewebauthn/server": "13.1.1",
|
|
22
|
-
"@toa.io/core": "1.0.0-alpha.
|
|
22
|
+
"@toa.io/core": "1.0.0-alpha.252",
|
|
23
23
|
"@toa.io/generic": "1.0.0-alpha.225",
|
|
24
24
|
"@toa.io/schemas": "1.0.0-alpha.246",
|
|
25
25
|
"bcryptjs": "2.4.3",
|
|
@@ -32,17 +32,18 @@
|
|
|
32
32
|
"minimatch": "10.2.4",
|
|
33
33
|
"msgpackr": "1.11.9",
|
|
34
34
|
"negotiator": "1.0.0",
|
|
35
|
-
"openspan": "1.0.0-alpha.
|
|
35
|
+
"openspan": "1.0.0-alpha.252",
|
|
36
36
|
"paseto": "3.1.4"
|
|
37
37
|
},
|
|
38
38
|
"scripts": {
|
|
39
39
|
"test": "jest",
|
|
40
|
-
"transpile": "tsc && npm run transpile:bans && npm run transpile:basic && npm run transpile:tokens && npm run transpile:roles && npm run transpile:federation && npm run transpile:keys && npm run transpile:passkeys && npm run transpile:otp",
|
|
40
|
+
"transpile": "tsc && npm run transpile:bans && npm run transpile:basic && npm run transpile:tokens && npm run transpile:roles && npm run transpile:federation && npm run transpile:credentials && npm run transpile:keys && npm run transpile:passkeys && npm run transpile:otp",
|
|
41
41
|
"transpile:bans": "tsc -p ./components/identity.bans",
|
|
42
42
|
"transpile:basic": "tsc -p ./components/identity.basic",
|
|
43
43
|
"transpile:tokens": "tsc -p ./components/identity.tokens",
|
|
44
44
|
"transpile:roles": "tsc -p ./components/identity.roles",
|
|
45
45
|
"transpile:federation": "tsc -p ./components/identity.federation",
|
|
46
|
+
"transpile:credentials": "tsc -p ./components/identity.credentials",
|
|
46
47
|
"transpile:keys": "tsc -p ./components/identity.keys",
|
|
47
48
|
"transpile:passkeys": "tsc -p ./components/identity.passkeys",
|
|
48
49
|
"transpile:otp": "tsc -p ./components/identity.otp",
|
|
@@ -64,5 +65,5 @@
|
|
|
64
65
|
},
|
|
65
66
|
"testEnvironment": "node"
|
|
66
67
|
},
|
|
67
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "753e94e44b499be02dee28fa1db2d45c053434cf"
|
|
68
69
|
}
|