Skip to content

Commit

Permalink
Add option to use custom webId (#3)
Browse files Browse the repository at this point in the history
The optional second parameter is the issuer, matching service's origin.
  • Loading branch information
mrkvon authored Nov 2, 2024
1 parent 9d66780 commit 8660590
Show file tree
Hide file tree
Showing 10 changed files with 474 additions and 32 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ There are three endpoints that need to be set up:

- `/.well-known/openid-configuration`
- `/path/to/jwks`
- `/path/to/webId`
- `/path/to/webId` - unless you want to use custom webId

For more details, you can check the output of `getEndpoints(webId)` from the `@soid/core` package.
For more details, you can check the output of `getEndpoints(webId: string, issuer?: string)` from the `@soid/core` package.

## Limitations

Expand Down
42 changes: 41 additions & 1 deletion packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,35 @@

Give your Solid service a Solid-OIDC-compatible identity.

## Overview

This library:

- tells you which endpoints your service has to serve: `getEndpoints(webId: string, issuer?: string)`
- provides authenticated fetch that your service can use to access protected resources: `await getAuthenticatedFetch(webId: string, issuer?: string)`

Please consider using higher-level libraries like [`@soid/koa`](https://npmjs.com/package/@soid/koa).

## Usage

### Installation

```bash
npm install --save @soid/core
# or
yarn add @soid/core
```

### Identity for service's own webId

By default, your service can serve its own webId.

```ts
import { getEndpoints, getAuthenticatedFetch } from '@soid/core'

// The webId's origin has to match the service's origin
const webId = 'https://service.example/profile/card#bot'

// Get authenticated fetch to make requests with this identity
const authenticatedFetch = await getAuthenticatedFetch(webId)

Expand All @@ -24,4 +47,21 @@ const endpoints = getEndpoints(webId)
// }]
```

Please consider using higher-level libraries like [`@soid/koa`](https://npmjs.com/package/@soid/koa).
### Identity for custom webId

You can also authenticate your service with custom webId, such as your personal webId.

You MUST add triple `<webId> solid:oidcIssuer <issuer>.` to your webId, where `issuer` MUST match the origin of the service. (no trailing slashes!)

```ts
import { getEndpoints, getAuthenticatedFetch } from '@soid/core'

const webId = 'https://custom.webid/profile/card#me' // you'll have to serve this somewhere, and add the required triple
const issuer = 'https://service.example' // this has to match your service's origin

// Get authenticated fetch to make requests with this identity
const authenticatedFetch = await getAuthenticatedFetch(webId, issuer)

// Get configuration of endpoints that your service MUST serve
const endpoints = getEndpoints(webId, issuer)
```
24 changes: 17 additions & 7 deletions packages/core/src/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,22 @@ export interface Endpoint {
defaultContentType: string
}

export const getEndpoints = (webId: string): Endpoint[] => {
export const getEndpoints = (webId: string, issuer?: string): Endpoint[] => {
const { pathname, hash, origin } = new URL(webId)

return [
issuer = issuer ? new URL(issuer).origin : origin

// make sure that issuer doesn't contain any unwanted paths etc.
issuer = new URL(issuer).origin

const endpoints: Endpoint[] = [
{
method: 'get',
path: '/.well-known/openid-configuration',
body: {
'application/json': {
issuer: origin,
jwks_uri: new URL('/jwks', webId).toString(),
issuer,
jwks_uri: new URL('/jwks', issuer).toString(),
response_types_supported: ['id_token', 'token'],
scopes_supported: ['openid', 'webid'],
},
Expand All @@ -30,7 +35,10 @@ export const getEndpoints = (webId: string): Endpoint[] => {
body: { 'application/json': { keys: [fullJwkPublicKey] } },
defaultContentType: 'application/json',
},
{
]

if (issuer === origin) {
endpoints.push({
method: 'get',
path: pathname,
body: {
Expand All @@ -46,6 +54,8 @@ export const getEndpoints = (webId: string): Endpoint[] => {
},
// TODO add application/ld+json
defaultContentType: 'text/turtle',
},
]
})
}

return endpoints
}
7 changes: 5 additions & 2 deletions packages/core/src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ export const fullJwkPublicKey = {

export const getAuthenticatedFetch = async (
webId: string,
issuer?: string,
): Promise<typeof globalThis.fetch> => {
const { origin: baseUrl } = new URL(webId)
const { origin } = new URL(webId)

issuer = issuer ? new URL(issuer).origin : origin
const dpopKey = await generateDpopKeyPair()

const jkt = await calculateJwkThumbprint(
Expand All @@ -42,7 +45,7 @@ export const getAuthenticatedFetch = async (
.setIssuedAt(now)
.setExpirationTime(now + 3600)
.setAudience('solid')
.setIssuer(baseUrl)
.setIssuer(issuer)
.setJti(randomUUID())
.sign(tokenKeyPair.privateKey)

Expand Down
5 changes: 1 addition & 4 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,2 @@
export {
fullJwkPublicKey as jwkPublicKey,
getAuthenticatedFetch,
} from './identity.js'
export { getEndpoints, type Endpoint } from './endpoints.js'
export { getAuthenticatedFetch } from './identity.js'
54 changes: 53 additions & 1 deletion packages/koa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,35 @@

Give your koa-based Solid service a Solid-OIDC-compatible identity.

## Overview

This library provides:

- identity-serving middleware for your koa-based service: `solidIdentity(webId: string, issuer?: string)`
- authenticated fetch that your service can use to access protected resources: `await getAuthenticatedFetch(webId: string, issuer?: string)`

If you want to serve identity for a koa-incompatible service, consider using lower level [`@soid/core`](https://npmjs.com/package/@soid/core), or [open an issue](https://github.com/solidcouch/solid-identity/issues).

## Usage

### Installation

```bash
npm install --save @soid/koa
# or
yarn add @soid/koa
```

### Identity for service's own webId

By default, your service can serve its own webId.

```ts
import Koa from 'koa'
import Router from '@koa/router'
import { solidIdentity, getAuthenticatedFetch } from '@soid/koa'

// The webId origin MUST match your service origin
const webId = 'https://service.example/profile/card#bot'

const app = new Koa()
Expand All @@ -19,8 +41,38 @@ router.use(solidIdentity(webId).routes())
// register your other routes
// ...

app.use(router)
app.use(router.routes()).use(router.allowedMethods())

// use the authenticated fetch to make authenticated requests to Solid Pods or other Solid-compatible services
const fetch = getAuthenticatedFetch(webId)
```

### Identity for custom webId

You can also authenticate your service with custom webId (for example your own webId)

You MUST add triple `<webId> solid:oidcIssuer <issuer>.` to your webId, where `issuer` MUST match the origin of the service. (no trailing slashes!)

```ts
import Koa from 'koa'
import Router from '@koa/router'
import { solidIdentity, getAuthenticatedFetch } from '@soid/koa'

// The webId must serve a profile in text/turtle, and has to contain the required triple pointing to the issuer
const webId = 'https://custom.webid/profile/card#me'
// The issuer has to match your service's origin
const issuer = 'https://service.example'

const app = new Koa()
const router = new Router()

// register the identity middleware in your router
router.use(solidIdentity(webId, issuer).routes())
// register your other routes
// ...

app.use(router.routes()).use(router.allowedMethods())

// use the authenticated fetch to make authenticated requests to Solid Pods or other Solid-compatible services
const fetch = getAuthenticatedFetch(webId, issuer)
```
1 change: 1 addition & 0 deletions packages/koa/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"@types/koa__router": "^12.0.4",
"css-authn": "^0.0.16",
"koa": "^2.15.3",
"msw": "^2.6.0",
"rdf-namespaces": "^1.12.0",
"typescript": "^5.6.2",
"vitest": "^2.1.4"
Expand Down
4 changes: 2 additions & 2 deletions packages/koa/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import Router from '@koa/router'
import { getEndpoints } from '@soid/core'
export { getAuthenticatedFetch } from '@soid/core'

export const solidIdentity = (identity: string) => {
export const solidIdentity = (webId: string, issuer?: string) => {
const router = new Router()

const endpoints = getEndpoints(identity)
const endpoints = getEndpoints(webId, issuer)

for (const endpoint of endpoints) {
router[endpoint.method](endpoint.path, async ctx => {
Expand Down
Loading

0 comments on commit 8660590

Please sign in to comment.