Skip to content

Commit 5c5f5d5

Browse files
Initial release: solid-oidc v0.0.1
Minimal, zero-build Solid-OIDC client for browsers (~500 lines). Features: - Complete Solid-OIDC authentication flow - DPoP bound tokens (RFC 9449) - PKCE (RFC 7636) - Session persistence via IndexedDB - Token refresh support - Event-driven state management Based on solid-oidc-client-browser by uvdsl (Christoph Braun).
0 parents  commit 5c5f5d5

File tree

7 files changed

+1430
-0
lines changed

7 files changed

+1430
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
.DS_Store
3+
*.log

LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
MIT License
2+
3+
Copyright (c) 2024 JavaScriptSolidServer
4+
Copyright (c) 2024 Christoph Braun (uvdsl)
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.

README.md

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
# solid-oidc
2+
3+
Minimal, zero-build Solid-OIDC client for browsers.
4+
5+
A single JavaScript file (~500 lines) that handles the complete Solid-OIDC authentication flow. No bundler, no transpiler, no build step required.
6+
7+
## Features
8+
9+
- **Zero build step** - Just import and use
10+
- **Single file** - Copy `solid-oidc.js` or import from CDN
11+
- **~500 lines** - Readable, auditable, hackable
12+
- **Full Solid-OIDC** - Login, logout, token refresh, authenticated fetch
13+
- **DPoP bound tokens** - Secure proof-of-possession
14+
- **Persistent sessions** - Survives page refresh via IndexedDB
15+
- **Event-driven** - React to session state changes
16+
17+
## Quick Start
18+
19+
```html
20+
<!DOCTYPE html>
21+
<html>
22+
<head>
23+
<title>Solid App</title>
24+
</head>
25+
<body>
26+
<button id="login">Login</button>
27+
<button id="logout" hidden>Logout</button>
28+
<pre id="output"></pre>
29+
30+
<script type="module">
31+
import { Session } from 'https://esm.sh/gh/JavaScriptSolidServer/solid-oidc/solid-oidc.js'
32+
33+
const session = new Session({
34+
onStateChange: (e) => {
35+
document.getElementById('login').hidden = e.detail.isActive
36+
document.getElementById('logout').hidden = !e.detail.isActive
37+
document.getElementById('output').textContent = e.detail.isActive
38+
? `Logged in as ${e.detail.webId}`
39+
: 'Not logged in'
40+
}
41+
})
42+
43+
// Try to restore previous session
44+
session.restore().catch(() => {})
45+
46+
// Handle redirect from identity provider
47+
session.handleRedirectFromLogin()
48+
49+
// Login button
50+
document.getElementById('login').onclick = () => {
51+
session.login('https://solidcommunity.net', window.location.href)
52+
}
53+
54+
// Logout button
55+
document.getElementById('logout').onclick = () => {
56+
session.logout()
57+
}
58+
</script>
59+
</body>
60+
</html>
61+
```
62+
63+
## Installation
64+
65+
### Option 1: CDN (Recommended)
66+
67+
```js
68+
import { Session } from 'https://esm.sh/gh/JavaScriptSolidServer/solid-oidc/solid-oidc.js'
69+
```
70+
71+
### Option 2: npm
72+
73+
```bash
74+
npm install solid-oidc
75+
```
76+
77+
```js
78+
import { Session } from 'solid-oidc'
79+
```
80+
81+
### Option 3: Copy the file
82+
83+
Just copy `solid-oidc.js` into your project and import it:
84+
85+
```js
86+
import { Session } from './solid-oidc.js'
87+
```
88+
89+
## API Reference
90+
91+
### `new Session(options)`
92+
93+
Create a new session instance.
94+
95+
```js
96+
const session = new Session({
97+
// Optional: Pre-registered client_id (skips dynamic registration)
98+
clientId: 'https://myapp.example/id',
99+
100+
// Optional: Custom database for session persistence
101+
database: new SessionDatabase('my-app'),
102+
103+
// Optional: Event callbacks
104+
onStateChange: (event) => console.log(event.detail),
105+
onExpirationWarning: (event) => console.log('Expiring in', event.detail.expires_in),
106+
onExpiration: () => console.log('Session expired')
107+
})
108+
```
109+
110+
### `session.login(idp, redirectUri)`
111+
112+
Redirect user to identity provider for authentication.
113+
114+
```js
115+
await session.login('https://solidcommunity.net', window.location.href)
116+
```
117+
118+
**Parameters:**
119+
- `idp` - Identity provider URL (e.g., `https://solidcommunity.net`)
120+
- `redirectUri` - URL to redirect back to after login
121+
122+
### `session.handleRedirectFromLogin()`
123+
124+
Handle the redirect from the identity provider. Call this on page load.
125+
126+
```js
127+
await session.handleRedirectFromLogin()
128+
```
129+
130+
### `session.restore()`
131+
132+
Restore a previous session using stored refresh token.
133+
134+
```js
135+
try {
136+
await session.restore()
137+
console.log('Session restored')
138+
} catch (error) {
139+
console.log('No session to restore')
140+
}
141+
```
142+
143+
### `session.logout()`
144+
145+
End the session and clear all stored data.
146+
147+
```js
148+
await session.logout()
149+
```
150+
151+
### `session.authFetch(url, options)`
152+
153+
Make an authenticated fetch request. Automatically includes DPoP proof and access token.
154+
155+
```js
156+
const response = await session.authFetch('https://pod.example/private/data.ttl')
157+
const data = await response.text()
158+
```
159+
160+
Falls back to regular `fetch()` if no session is active.
161+
162+
### Properties
163+
164+
| Property | Type | Description |
165+
|----------|------|-------------|
166+
| `session.isActive` | `boolean` | Whether user is logged in |
167+
| `session.webId` | `string \| null` | User's WebID when logged in |
168+
169+
### Methods
170+
171+
| Method | Returns | Description |
172+
|--------|---------|-------------|
173+
| `session.isExpired()` | `boolean` | Whether access token is expired |
174+
| `session.getExpiresIn()` | `number` | Seconds until token expires (-1 if no token) |
175+
176+
### Events
177+
178+
The session extends `EventTarget` and emits these events:
179+
180+
| Event | Detail | Description |
181+
|-------|--------|-------------|
182+
| `sessionStateChange` | `{ isActive, webId }` | Login/logout occurred |
183+
| `sessionExpirationWarning` | `{ expires_in }` | Token refresh failed but not expired |
184+
| `sessionExpiration` | - | Token expired and refresh failed |
185+
186+
```js
187+
session.addEventListener('sessionStateChange', (event) => {
188+
console.log('Active:', event.detail.isActive)
189+
console.log('WebID:', event.detail.webId)
190+
})
191+
```
192+
193+
## Advanced Usage
194+
195+
### Custom Session Database
196+
197+
```js
198+
import { Session, SessionDatabase } from './solid-oidc.js'
199+
200+
// Use a custom database name (useful for multiple sessions)
201+
const database = new SessionDatabase('my-app-session')
202+
const session = new Session({ database })
203+
```
204+
205+
### Pre-registered Client ID
206+
207+
If your app has a pre-registered client ID, provide it to skip dynamic registration:
208+
209+
```js
210+
const session = new Session({
211+
clientId: 'https://myapp.example/id'
212+
})
213+
```
214+
215+
### Multiple Identity Providers
216+
217+
```js
218+
const providers = [
219+
{ name: 'Solid Community', url: 'https://solidcommunity.net' },
220+
{ name: 'Inrupt PodSpaces', url: 'https://login.inrupt.com' },
221+
{ name: 'solidweb.org', url: 'https://solidweb.org' }
222+
]
223+
224+
// Let user choose
225+
const idp = prompt('Choose provider:', providers[0].url)
226+
await session.login(idp, window.location.href)
227+
```
228+
229+
### Handling Token Expiration
230+
231+
```js
232+
const session = new Session({
233+
onExpirationWarning: async (event) => {
234+
console.log(`Token expires in ${event.detail.expires_in}s, refreshing...`)
235+
try {
236+
await session.restore()
237+
} catch {
238+
// Refresh failed, maybe prompt re-login
239+
if (confirm('Session expired. Login again?')) {
240+
await session.login(idp, window.location.href)
241+
}
242+
}
243+
}
244+
})
245+
```
246+
247+
## Specifications Implemented
248+
249+
- [RFC 6749](https://tools.ietf.org/html/rfc6749) - OAuth 2.0
250+
- [RFC 7636](https://tools.ietf.org/html/rfc7636) - PKCE
251+
- [RFC 9207](https://tools.ietf.org/html/rfc9207) - Authorization Server Issuer Identification
252+
- [RFC 9449](https://tools.ietf.org/html/rfc9449) - DPoP (Demonstration of Proof-of-Possession)
253+
- [Solid-OIDC](https://solidproject.org/TR/oidc) - Solid OIDC Specification
254+
255+
## Testing
256+
257+
Open `test.html` in a browser to run the test suite. Tests cover:
258+
- Session instantiation and state management
259+
- SessionDatabase (IndexedDB) operations
260+
- Event dispatching
261+
262+
```bash
263+
# Serve locally and open test.html
264+
npx serve .
265+
# Then visit http://localhost:3000/test.html
266+
```
267+
268+
## Browser Requirements
269+
270+
- ES Modules (`<script type="module">`)
271+
- `crypto.subtle` (requires HTTPS or localhost)
272+
- `indexedDB` (for session persistence)
273+
274+
Works in all modern browsers (Chrome 63+, Firefox 57+, Safari 11+, Edge 79+).
275+
276+
## Credits
277+
278+
Based on [solid-oidc-client-browser](https://github.com/uvdsl/solid-oidc-client-browser) by [uvdsl (Christoph Braun)](https://github.com/uvdsl). Refactored into a minimal, zero-dependency, single-file library.
279+
280+
## License
281+
282+
MIT

0 commit comments

Comments
 (0)