javascript-solid-server 0.0.110 → 0.0.112
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/.claude/settings.local.json +2 -1
- package/README.md +70 -1358
- package/bin/jss.js +1 -5
- package/docs/activitypub.md +109 -0
- package/docs/architecture.md +165 -0
- package/docs/authentication.md +157 -0
- package/docs/configuration.md +434 -0
- package/docs/invites.md +43 -0
- package/docs/mashlib.md +58 -0
- package/docs/mongodb.md +42 -0
- package/docs/nostr.md +56 -0
- package/docs/notifications.md +50 -0
- package/docs/payments.md +94 -0
- package/docs/quotas.md +36 -0
- package/docs/remotestorage.md +86 -0
- package/docs/security.md +96 -0
- package/docs/webrtc.md +66 -0
- package/package.json +1 -1
- package/src/auth/middleware.js +4 -7
- package/src/config.js +1 -6
- package/src/handlers/resource.js +7 -13
- package/src/server.js +11 -74
package/bin/jss.js
CHANGED
|
@@ -53,12 +53,10 @@ program
|
|
|
53
53
|
.option('--subdomains', 'Enable subdomain-based pods (XSS protection)')
|
|
54
54
|
.option('--no-subdomains', 'Disable subdomain-based pods')
|
|
55
55
|
.option('--base-domain <domain>', 'Base domain for subdomain pods (e.g., "example.com")')
|
|
56
|
-
.option('--mashlib', 'Enable Mashlib data browser (
|
|
57
|
-
.option('--mashlib-cdn', 'Enable Mashlib data browser (CDN mode, no local files needed)')
|
|
56
|
+
.option('--mashlib-cdn', 'Enable Mashlib data browser (CDN mode)')
|
|
58
57
|
.option('--mashlib-module <url>', 'Enable ES module data browser from a URL')
|
|
59
58
|
.option('--no-mashlib', 'Disable Mashlib data browser')
|
|
60
59
|
.option('--mashlib-version <version>', 'Mashlib version for CDN mode (default: 2.0.0)')
|
|
61
|
-
.option('--solidos-ui', 'Enable modern Nextcloud-style UI (requires --mashlib)')
|
|
62
60
|
.option('--git', 'Enable Git HTTP backend (clone/push support)')
|
|
63
61
|
.option('--no-git', 'Disable Git HTTP backend')
|
|
64
62
|
.option('--nostr', 'Enable Nostr relay')
|
|
@@ -143,7 +141,6 @@ program
|
|
|
143
141
|
mashlibCdn: config.mashlibCdn,
|
|
144
142
|
mashlibVersion: config.mashlibVersion,
|
|
145
143
|
mashlibModule: config.mashlibModule,
|
|
146
|
-
solidosUi: config.solidosUi,
|
|
147
144
|
git: config.git,
|
|
148
145
|
nostr: config.nostr,
|
|
149
146
|
nostrPath: config.nostrPath,
|
|
@@ -193,7 +190,6 @@ program
|
|
|
193
190
|
console.log(` Mashlib: local (data browser enabled)`);
|
|
194
191
|
}
|
|
195
192
|
if (config.mashlibModule) console.log(` Mashlib module: ${config.mashlibModule}`);
|
|
196
|
-
if (config.solidosUi) console.log(' SolidOS UI: enabled (modern interface)');
|
|
197
193
|
if (config.git) console.log(' Git: enabled (clone/push support)');
|
|
198
194
|
if (config.nostr) console.log(` Nostr: enabled (${config.nostrPath})`);
|
|
199
195
|
if (config.webrtc) console.log(` WebRTC: enabled (${config.webrtcPath || '/.webrtc'})`);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
## ActivityPub Federation
|
|
2
|
+
|
|
3
|
+
Enable ActivityPub to federate with Mastodon, Pleroma, Misskey, and other Fediverse servers:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
jss start --activitypub --ap-username alice --ap-display-name "Alice" --ap-summary "Hello from JSS!"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
### Endpoints
|
|
10
|
+
|
|
11
|
+
| Endpoint | Description |
|
|
12
|
+
|----------|-------------|
|
|
13
|
+
| `/.well-known/webfinger` | Actor discovery (Mastodon searches here) |
|
|
14
|
+
| `/.well-known/nodeinfo` | NodeInfo discovery |
|
|
15
|
+
| `/profile/card` | Actor (returns JSON-LD when `Accept: application/activity+json`) |
|
|
16
|
+
| `/inbox` | Shared inbox for receiving activities |
|
|
17
|
+
| `/profile/card/inbox` | Personal inbox |
|
|
18
|
+
| `/profile/card/outbox` | User's activities |
|
|
19
|
+
| `/profile/card/followers` | Followers collection |
|
|
20
|
+
| `/profile/card/following` | Following collection |
|
|
21
|
+
|
|
22
|
+
### How It Works
|
|
23
|
+
|
|
24
|
+
1. **Discovery**: Mastodon looks up `@alice@your.server` via WebFinger
|
|
25
|
+
2. **Actor**: Returns ActivityPub Actor JSON-LD with public key
|
|
26
|
+
3. **Follow**: Remote servers POST Follow activities to inbox
|
|
27
|
+
4. **Accept**: JSS auto-accepts follows and sends Accept back
|
|
28
|
+
5. **Delivery**: Posts are signed with HTTP Signatures and delivered to follower inboxes
|
|
29
|
+
|
|
30
|
+
### Identity Linking
|
|
31
|
+
|
|
32
|
+
Your WebID (`/profile/card#me`) becomes your ActivityPub Actor. Link to Nostr identity:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
jss start --activitypub --ap-nostr-pubkey <64-char-hex-pubkey>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This adds `alsoKnownAs: ["did:nostr:<pubkey>"]` to your Actor profile, creating a verifiable link between your Solid, ActivityPub, and Nostr identities (the SAND stack).
|
|
39
|
+
|
|
40
|
+
### Programmatic Usage
|
|
41
|
+
|
|
42
|
+
```javascript
|
|
43
|
+
import { createServer } from 'javascript-solid-server';
|
|
44
|
+
|
|
45
|
+
const server = createServer({
|
|
46
|
+
activitypub: true,
|
|
47
|
+
apUsername: 'alice',
|
|
48
|
+
apDisplayName: 'Alice',
|
|
49
|
+
apSummary: 'Building the decentralized web!',
|
|
50
|
+
apNostrPubkey: 'abc123...' // Optional: links to did:nostr
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Testing Federation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Check WebFinger
|
|
58
|
+
curl "http://localhost:3000/.well-known/webfinger?resource=acct:alice@localhost:3000"
|
|
59
|
+
|
|
60
|
+
# Get Actor (AP format)
|
|
61
|
+
curl -H "Accept: application/activity+json" http://localhost:3000/profile/card
|
|
62
|
+
|
|
63
|
+
# Check NodeInfo
|
|
64
|
+
curl http://localhost:3000/.well-known/nodeinfo/2.1
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Mastodon-compatible API
|
|
68
|
+
|
|
69
|
+
JSS exposes Mastodon API endpoints so that Mastodon clients (Elk, Phanpy, Ice Cubes) can connect:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
jss start --activitypub --idp
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Endpoints
|
|
76
|
+
|
|
77
|
+
| Endpoint | Description |
|
|
78
|
+
|----------|-------------|
|
|
79
|
+
| `POST /api/v1/apps` | Dynamic client registration |
|
|
80
|
+
| `GET /api/v1/accounts/verify_credentials` | Current user profile |
|
|
81
|
+
| `GET /api/v1/instance` | Instance metadata |
|
|
82
|
+
| `GET /oauth/authorize` | OAuth authorize page |
|
|
83
|
+
| `POST /oauth/authorize` | Process login |
|
|
84
|
+
| `POST /oauth/token` | Exchange code for Bearer token |
|
|
85
|
+
|
|
86
|
+
### OAuth 2.0 Flow
|
|
87
|
+
|
|
88
|
+
The OAuth layer is shared between Mastodon clients, remoteStorage apps, and third-party Solid panes:
|
|
89
|
+
|
|
90
|
+
1. Client registers via `POST /api/v1/apps` (gets `client_id` + `client_secret`)
|
|
91
|
+
2. Client redirects user to `GET /oauth/authorize?client_id=...&redirect_uri=...&response_type=code`
|
|
92
|
+
3. User logs in, JSS redirects back with `?code=...`
|
|
93
|
+
4. Client exchanges code for Bearer token via `POST /oauth/token`
|
|
94
|
+
5. Bearer token works with all JSS endpoints (Solid, ActivityPub, remoteStorage)
|
|
95
|
+
|
|
96
|
+
Supports out-of-band (OOB) redirect for CLI/desktop clients.
|
|
97
|
+
|
|
98
|
+
### Testing
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Register a client
|
|
102
|
+
curl -X POST http://localhost:3000/api/v1/apps \
|
|
103
|
+
-H "Content-Type: application/json" \
|
|
104
|
+
-d '{"client_name": "Test App", "redirect_uris": "urn:ietf:wg:oauth:2.0:oob"}'
|
|
105
|
+
|
|
106
|
+
# Check instance info
|
|
107
|
+
curl http://localhost:3000/api/v1/instance
|
|
108
|
+
```
|
|
109
|
+
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
## Pod Structure
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
/alice/
|
|
5
|
+
├── index.html # WebID profile (HTML with JSON-LD)
|
|
6
|
+
├── .acl # Root ACL (owner + public read)
|
|
7
|
+
├── inbox/ # Notifications (public append)
|
|
8
|
+
│ └── .acl
|
|
9
|
+
├── public/ # Public files
|
|
10
|
+
├── private/ # Private files (owner only)
|
|
11
|
+
│ └── .acl
|
|
12
|
+
└── settings/ # User preferences (owner only)
|
|
13
|
+
├── .acl
|
|
14
|
+
├── prefs
|
|
15
|
+
├── publicTypeIndex
|
|
16
|
+
└── privateTypeIndex
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Project Structure
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
src/
|
|
23
|
+
├── index.js # Entry point
|
|
24
|
+
├── server.js # Fastify setup
|
|
25
|
+
├── handlers/
|
|
26
|
+
│ ├── resource.js # GET, PUT, DELETE, HEAD, PATCH
|
|
27
|
+
│ ├── container.js # POST, pod creation
|
|
28
|
+
│ ├── git.js # Git HTTP backend
|
|
29
|
+
│ └── pay.js # HTTP 402 paid access
|
|
30
|
+
├── storage/
|
|
31
|
+
│ ├── filesystem.js # File operations
|
|
32
|
+
│ └── quota.js # Storage quota management
|
|
33
|
+
├── auth/
|
|
34
|
+
│ ├── middleware.js # Auth hook
|
|
35
|
+
│ ├── token.js # Simple token auth
|
|
36
|
+
│ ├── solid-oidc.js # DPoP verification
|
|
37
|
+
│ ├── nostr.js # NIP-98 Nostr authentication
|
|
38
|
+
│ ├── did-nostr.js # did:nostr → WebID resolution
|
|
39
|
+
│ └── webid-tls.js # WebID-TLS client certificate auth
|
|
40
|
+
├── wac/
|
|
41
|
+
│ ├── parser.js # ACL parsing
|
|
42
|
+
│ └── checker.js # Permission checking
|
|
43
|
+
├── ldp/
|
|
44
|
+
│ ├── headers.js # LDP Link headers
|
|
45
|
+
│ └── container.js # Container JSON-LD
|
|
46
|
+
├── webid/
|
|
47
|
+
│ └── profile.js # WebID generation
|
|
48
|
+
├── patch/
|
|
49
|
+
│ ├── n3-patch.js # N3 Patch support
|
|
50
|
+
│ └── sparql-update.js # SPARQL Update support
|
|
51
|
+
├── notifications/
|
|
52
|
+
│ ├── index.js # WebSocket plugin
|
|
53
|
+
│ ├── events.js # Event emitter
|
|
54
|
+
│ └── websocket.js # solid-0.1 protocol
|
|
55
|
+
├── idp/
|
|
56
|
+
│ ├── index.js # Identity Provider plugin
|
|
57
|
+
│ ├── provider.js # oidc-provider config
|
|
58
|
+
│ ├── adapter.js # Filesystem adapter
|
|
59
|
+
│ ├── accounts.js # User account management
|
|
60
|
+
│ ├── credentials.js # Credentials endpoint
|
|
61
|
+
│ ├── keys.js # JWKS key management
|
|
62
|
+
│ ├── interactions.js # Login/consent handlers
|
|
63
|
+
│ ├── passkey.js # WebAuthn/FIDO2 passkey support
|
|
64
|
+
│ ├── views.js # HTML templates
|
|
65
|
+
│ └── invites.js # Invite code management
|
|
66
|
+
├── ap/
|
|
67
|
+
│ ├── index.js # ActivityPub plugin
|
|
68
|
+
│ ├── keys.js # RSA keypair management
|
|
69
|
+
│ ├── store.js # SQLite storage (followers, activities)
|
|
70
|
+
│ └── routes/
|
|
71
|
+
│ ├── actor.js # Actor JSON-LD
|
|
72
|
+
│ ├── inbox.js # Receive activities
|
|
73
|
+
│ ├── outbox.js # User's activities
|
|
74
|
+
│ ├── collections.js # Followers/following
|
|
75
|
+
│ ├── mastodon.js # Mastodon API (apps, instance, verify_credentials)
|
|
76
|
+
│ └── oauth.js # OAuth 2.0 authorize/token flow
|
|
77
|
+
├── webledger.js # Web Ledger balance tracking (webledgers.org)
|
|
78
|
+
├── mrc20.js # State chain verification
|
|
79
|
+
├── remotestorage.js # remoteStorage protocol (draft-dejong-remotestorage-22)
|
|
80
|
+
├── rdf/
|
|
81
|
+
│ ├── turtle.js # Turtle <-> JSON-LD
|
|
82
|
+
│ └── conneg.js # Content negotiation
|
|
83
|
+
├── mashlib/
|
|
84
|
+
│ └── index.js # Mashlib data browser plugin
|
|
85
|
+
└── utils/
|
|
86
|
+
├── url.js # URL utilities
|
|
87
|
+
├── conditional.js # If-Match/If-None-Match
|
|
88
|
+
└── ssrf.js # SSRF protection
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Dependencies
|
|
92
|
+
|
|
93
|
+
14 direct dependencies for a fast, secure server:
|
|
94
|
+
|
|
95
|
+
- **fastify** - High-performance HTTP server
|
|
96
|
+
- **@fastify/middie** - Express/Connect middleware bridge (for IdP)
|
|
97
|
+
- **@fastify/rate-limit** - Rate limiting for API endpoints
|
|
98
|
+
- **@fastify/websocket** - WebSocket support for notifications
|
|
99
|
+
- **@simplewebauthn/server** - Passkey/WebAuthn authentication
|
|
100
|
+
- **bcryptjs** - Password hashing (pure JS, works on Termux/Android)
|
|
101
|
+
- **commander** - CLI command parsing
|
|
102
|
+
- **fs-extra** - Enhanced file operations
|
|
103
|
+
- **jose** - JWT/JWK handling for Solid-OIDC
|
|
104
|
+
- **microfed** - ActivityPub primitives (only when activitypub enabled)
|
|
105
|
+
- **n3** - Turtle parsing (only used when conneg enabled)
|
|
106
|
+
- **nostr-tools** - Nostr protocol and Schnorr signature verification
|
|
107
|
+
- **oidc-provider** - OpenID Connect Identity Provider (only when IdP enabled)
|
|
108
|
+
- **sql.js** - SQLite storage for federation data (WASM, cross-platform)
|
|
109
|
+
|
|
110
|
+
## Performance
|
|
111
|
+
|
|
112
|
+
This server is designed for speed. Benchmark results on a typical development machine:
|
|
113
|
+
|
|
114
|
+
| Operation | Requests/sec | Avg Latency | p99 Latency |
|
|
115
|
+
|-----------|-------------|-------------|-------------|
|
|
116
|
+
| GET resource | 5,400+ | 1.2ms | 3ms |
|
|
117
|
+
| GET container | 4,700+ | 1.6ms | 3ms |
|
|
118
|
+
| PUT (write) | 5,700+ | 1.1ms | 2ms |
|
|
119
|
+
| POST (create) | 5,200+ | 1.3ms | 3ms |
|
|
120
|
+
| OPTIONS | 10,000+ | 0.4ms | 1ms |
|
|
121
|
+
|
|
122
|
+
Run benchmarks yourself:
|
|
123
|
+
```bash
|
|
124
|
+
npm run benchmark
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Running Tests
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
npm test
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Currently passing: **289 tests** (including 27 conformance tests)
|
|
134
|
+
|
|
135
|
+
### Conformance Test Harness (CTH)
|
|
136
|
+
|
|
137
|
+
This server passes the Solid Conformance Test Harness authentication tests:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# Start server with IdP and content negotiation
|
|
141
|
+
JSS_PORT=4000 JSS_CONNEG=true JSS_IDP=true jss start
|
|
142
|
+
|
|
143
|
+
# Create test users
|
|
144
|
+
curl -X POST http://localhost:4000/.pods \
|
|
145
|
+
-H "Content-Type: application/json" \
|
|
146
|
+
-d '{"name": "alice", "email": "alice@example.com", "password": "alicepassword123"}'
|
|
147
|
+
|
|
148
|
+
curl -X POST http://localhost:4000/.pods \
|
|
149
|
+
-H "Content-Type: application/json" \
|
|
150
|
+
-d '{"name": "bob", "email": "bob@example.com", "password": "bobpassword123"}'
|
|
151
|
+
|
|
152
|
+
# Run CTH authentication tests
|
|
153
|
+
docker run --rm --network=host \
|
|
154
|
+
-e SOLID_IDENTITY_PROVIDER="http://localhost:4000/" \
|
|
155
|
+
-e USERS_ALICE_WEBID="http://localhost:4000/alice/#me" \
|
|
156
|
+
-e USERS_ALICE_PASSWORD="alicepassword123" \
|
|
157
|
+
-e USERS_BOB_WEBID="http://localhost:4000/bob/#me" \
|
|
158
|
+
-e USERS_BOB_PASSWORD="bobpassword123" \
|
|
159
|
+
solidproject/conformance-test-harness:latest \
|
|
160
|
+
--filter="authentication"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**CTH Status (v0.0.15):**
|
|
164
|
+
- Authentication tests: 6/6 passing
|
|
165
|
+
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Authentication
|
|
2
|
+
|
|
3
|
+
### Simple Tokens (Development)
|
|
4
|
+
|
|
5
|
+
Use the token returned from pod creation:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:3000/alice/private/
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Built-in Identity Provider (v0.0.12+)
|
|
12
|
+
|
|
13
|
+
Enable the built-in Solid-OIDC Identity Provider:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
jss start --idp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
With IdP enabled, pod creation requires email and password:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
curl -X POST http://localhost:3000/.pods \
|
|
23
|
+
-H "Content-Type: application/json" \
|
|
24
|
+
-d '{"name": "alice", "email": "alice@example.com", "password": "secret123"}'
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Response:
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"name": "alice",
|
|
31
|
+
"webId": "http://localhost:3000/alice/#me",
|
|
32
|
+
"podUri": "http://localhost:3000/alice/",
|
|
33
|
+
"idpIssuer": "http://localhost:3000",
|
|
34
|
+
"loginUrl": "http://localhost:3000/idp/auth"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
OIDC Discovery: `/.well-known/openid-configuration`
|
|
39
|
+
|
|
40
|
+
### Programmatic Login (CTH Compatible)
|
|
41
|
+
|
|
42
|
+
For automated testing and scripts, use the credentials endpoint:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
curl -X POST http://localhost:3000/idp/credentials \
|
|
46
|
+
-H "Content-Type: application/json" \
|
|
47
|
+
-d '{"email": "alice@example.com", "password": "secret123"}'
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Response:
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"access_token": "...",
|
|
54
|
+
"token_type": "Bearer",
|
|
55
|
+
"expires_in": 3600,
|
|
56
|
+
"webid": "http://localhost:3000/alice/#me"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
For DPoP-bound tokens (Solid-OIDC compliant), include a DPoP proof header.
|
|
61
|
+
|
|
62
|
+
### Passkey Authentication (v0.0.77+)
|
|
63
|
+
|
|
64
|
+
Enable passwordless login with WebAuthn/FIDO2:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
jss start --idp
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**How it works:**
|
|
71
|
+
1. User logs in with username/password
|
|
72
|
+
2. Prompted to add a passkey (Touch ID, Face ID, security key)
|
|
73
|
+
3. Future logins: tap "Sign in with Passkey" → biometric → done!
|
|
74
|
+
|
|
75
|
+
**Benefits:**
|
|
76
|
+
- Phishing-resistant (bound to domain)
|
|
77
|
+
- No passwords to remember or leak
|
|
78
|
+
- Works on mobile and desktop
|
|
79
|
+
|
|
80
|
+
Passkeys are stored per-account and work across devices via platform sync (iCloud Keychain, Google Password Manager, etc.).
|
|
81
|
+
|
|
82
|
+
### Schnorr SSO (v0.0.79+)
|
|
83
|
+
|
|
84
|
+
Sign in with your Nostr key using NIP-07 browser extensions:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
jss start --idp
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**How it works:**
|
|
91
|
+
1. User clicks "Sign in with Schnorr" on the login page
|
|
92
|
+
2. NIP-07 extension (Podkey, nos2x, Alby) signs a NIP-98 auth event
|
|
93
|
+
3. Server verifies BIP-340 Schnorr signature
|
|
94
|
+
4. User authenticated via linked did:nostr identity
|
|
95
|
+
|
|
96
|
+
**Requirements:**
|
|
97
|
+
- Account must have a `did:nostr:<pubkey>` WebID linked
|
|
98
|
+
- User needs a NIP-07 compatible browser extension
|
|
99
|
+
|
|
100
|
+
**Benefits:**
|
|
101
|
+
- No passwords - cryptographic authentication
|
|
102
|
+
- Works with existing Nostr identity
|
|
103
|
+
- Single sign-on across Solid and Nostr ecosystems
|
|
104
|
+
|
|
105
|
+
### Solid-OIDC (External IdP)
|
|
106
|
+
|
|
107
|
+
The server also accepts DPoP-bound access tokens from external Solid identity providers:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
curl -H "Authorization: DPoP ACCESS_TOKEN" \
|
|
111
|
+
-H "DPoP: DPOP_PROOF" \
|
|
112
|
+
http://localhost:3000/alice/private/
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### WebID-TLS (Client Certificates)
|
|
116
|
+
|
|
117
|
+
For backend services, CLI tools, and automated agents that need non-interactive authentication:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
jss start --ssl-key key.pem --ssl-cert cert.pem --webid-tls
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**How it works:**
|
|
124
|
+
1. Client presents X.509 certificate during TLS handshake
|
|
125
|
+
2. Certificate's `SubjectAlternativeName` contains a WebID URI
|
|
126
|
+
3. Server fetches the WebID profile
|
|
127
|
+
4. Server verifies the certificate's public key matches one in the profile
|
|
128
|
+
|
|
129
|
+
**Testing with curl:**
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Generate self-signed cert with WebID in SAN
|
|
133
|
+
openssl req -x509 -newkey rsa:2048 -keyout client-key.pem -out client-cert.pem -days 365 \
|
|
134
|
+
-subj "/CN=Test" -addext "subjectAltName=URI:https://example.com/alice/#me" -nodes
|
|
135
|
+
|
|
136
|
+
# Make authenticated request
|
|
137
|
+
curl --cert client-cert.pem --key client-key.pem https://localhost:8443/alice/private/
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**Profile requirement:** Your WebID profile must contain the certificate's public key:
|
|
141
|
+
|
|
142
|
+
```turtle
|
|
143
|
+
@prefix cert: <http://www.w3.org/ns/auth/cert#> .
|
|
144
|
+
|
|
145
|
+
<#me> cert:key [
|
|
146
|
+
a cert:RSAPublicKey;
|
|
147
|
+
cert:modulus "abc123..."^^xsd:hexBinary;
|
|
148
|
+
cert:exponent 65537
|
|
149
|
+
] .
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
**Use cases:**
|
|
153
|
+
- Enterprise backend services with existing PKI
|
|
154
|
+
- Server-to-server communication
|
|
155
|
+
- CLI tools and scripts
|
|
156
|
+
- IoT devices with embedded certificates
|
|
157
|
+
|