Serve a Solid-OIDC Client ID Document at /app for the OIDC adapter fetch, keeping the app actor for SAI
This commit is contained in:
@@ -2,6 +2,21 @@ const urlJoin = require('url-join');
|
||||
const { AppService } = require('@activitypods/app');
|
||||
const CONFIG = require('../config/config');
|
||||
|
||||
// `GET /app` has two personalities, discriminated by the request's `JsonLdContext` header.
|
||||
//
|
||||
// 1. Solid-OIDC Client ID Document. The pod provider's OIDC adapter (RedisAdapter.find)
|
||||
// resolves an unknown `client_id` that starts with `http` by fetching it, sending
|
||||
// `Accept: application/ld+json` and `JsonLdContext: https://www.w3.org/ns/solid/oidc-context.jsonld`.
|
||||
// The pod provider runs the login with `client_id = <HOME_URL>/app`, so this same URL must,
|
||||
// for that fetch, return a document whose `@context` literally includes the Solid-OIDC
|
||||
// context, whose `client_id` equals the fetched URI exactly, and which carries `redirect_uris`.
|
||||
// Anything else fails `invalid_client_metadata / client_id is mandatory property`.
|
||||
//
|
||||
// 2. SAI app description (the actor). The pod provider's auth-agent fetches this URL
|
||||
// WITHOUT the `JsonLdContext` header (`ldp.remote.getNetwork`) to install/describe the app,
|
||||
// and expects the app actor document served today (`type: [Application, interop:Application]`).
|
||||
//
|
||||
// The `JsonLdContext` header is the only discriminator: same path, two representations.
|
||||
module.exports = {
|
||||
mixins: [AppService],
|
||||
settings: {
|
||||
@@ -47,5 +62,34 @@ module.exports = {
|
||||
optional: []
|
||||
},
|
||||
queueServiceUrl: CONFIG.QUEUE_SERVICE_URL
|
||||
},
|
||||
actions: {
|
||||
// Overrides the mixin's `get` (which returns `this.appActor` for every request) to
|
||||
// answer the Solid-OIDC Client ID Document fetch as well. `this.appActor` is set by the
|
||||
// mixin's `started()`, i.e. long before any request is served.
|
||||
get: {
|
||||
handler(ctx) {
|
||||
// moleculer-web exposes the raw request only when the route alias sets
|
||||
// passReqResToParams (see services/core/core.service.js). Internal calls
|
||||
// (ctx.call('app.get')) have no `$req`, so they always get the actor.
|
||||
const req = ctx.params && ctx.params.$req;
|
||||
const headers = (req && req.headers) || {};
|
||||
const jsonLdContextKey = Object.keys(headers).find(key => key.toLowerCase() === 'jsonldcontext');
|
||||
const isOidcClientIdDocument =
|
||||
jsonLdContextKey !== undefined && String(headers[jsonLdContextKey]).includes('solid/oidc-context.jsonld');
|
||||
|
||||
if (isOidcClientIdDocument) {
|
||||
return {
|
||||
'@context': ['https://www.w3.org/ns/solid/oidc-context.jsonld'],
|
||||
client_id: urlJoin(CONFIG.HOME_URL, 'app'),
|
||||
redirect_uris: [urlJoin(CONFIG.FRONT_URL, 'login')],
|
||||
client_name: CONFIG.APP_NAME,
|
||||
client_uri: CONFIG.FRONT_URL
|
||||
};
|
||||
}
|
||||
|
||||
return this.appActor;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user