Skip to content

Commit

Permalink
WIP readme
Browse files Browse the repository at this point in the history
  • Loading branch information
mrkvon committed Nov 1, 2024
1 parent b69bed6 commit f6412af
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 19 deletions.
34 changes: 33 additions & 1 deletion packages/core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,27 @@

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

## Overview

This library:

- tells you which endpoints your service has to serve
- provides authenticated fetch that your service can use to access protected resources

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

## Usage

### 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 +39,21 @@ const endpoints = getEndpoints(webId)
// }]
```

Please consider using higher-level libraries like [`@soid/koa`](https://npmjs.com/package/@soid/koa).
### 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 { 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)
```
13 changes: 9 additions & 4 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, baseUrl?: string): Endpoint[] => {
export const getEndpoints = (webId: string, issuer?: string): Endpoint[] => {
const { pathname, hash, origin } = new URL(webId)

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: baseUrl ?? origin,
jwks_uri: new URL('/jwks', baseUrl ?? origin).toString(),
issuer,
jwks_uri: new URL('/jwks', issuer).toString(),
response_types_supported: ['id_token', 'token'],
scopes_supported: ['openid', 'webid'],
},
Expand All @@ -32,7 +37,7 @@ export const getEndpoints = (webId: string, baseUrl?: string): Endpoint[] => {
},
]

if (!baseUrl) {
if (issuer === origin) {
endpoints.push({
method: 'get',
path: pathname,
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ export const fullJwkPublicKey = {

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

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

const jkt = await calculateJwkThumbprint(
Expand All @@ -45,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'
35 changes: 34 additions & 1 deletion packages/koa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ Give your koa-based Solid service a Solid-OIDC-compatible identity.

## Usage

### 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 +24,36 @@ 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)
```

### 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'

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

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)
```
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, baseUrl?: string) => {
export const solidIdentity = (webId: string, issuer?: string) => {
const router = new Router()

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

for (const endpoint of endpoints) {
router[endpoint.method](endpoint.path, async ctx => {
Expand Down
6 changes: 2 additions & 4 deletions packages/koa/src/tests/identity.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Router from '@koa/router'
import { App, AppRunner, joinFilePath } from '@solid/community-server'
import Koa from 'koa'
import * as msw from 'msw'
Expand Down Expand Up @@ -41,9 +40,8 @@ beforeEach(async () => {

const setupServer = (...props: Parameters<typeof solidIdentity>) => {
const app = new Koa()
const router = new Router()
router.use(solidIdentity(...props).routes())
app.use(router.allowedMethods()).use(router.routes())
const identity = solidIdentity(...props)
app.use(identity.allowedMethods()).use(identity.routes())
return app
}

Expand Down

0 comments on commit f6412af

Please sign in to comment.