mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(core): support comma separated resource param (#5773)
This commit is contained in:
parent
9cf03c8edb
commit
b575f57ac3
4 changed files with 92 additions and 0 deletions
9
.changeset/rare-lamps-worry.md
Normal file
9
.changeset/rare-lamps-worry.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
"@logto/core": patch
|
||||
---
|
||||
|
||||
Support comma separated resource parameter
|
||||
|
||||
Some third-party libraries or plugins do not support array of resources, and can only specify `resource` through `additionalParameters` config, e.g. `flutter-appauth`. However, only one resource can be specified at a time in this way. This PR enables comma separated resource parameter support in Logto core service, so that multiple resources can be specified via a single string.
|
||||
|
||||
For example: Auth URL like `/oidc/auth?resource=https://example.com/api1,https://example.com/api2` will be interpreted and parsed to Logto core service as `/ordc/auth?resource=https://example.com/api1&resource=https://example.com/api2`.
|
45
packages/core/src/middleware/koa-resource-param.test.ts
Normal file
45
packages/core/src/middleware/koa-resource-param.test.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
import createMockContext from '#src/test-utils/jest-koa-mocks/create-mock-context.js';
|
||||
|
||||
const { jest } = import.meta;
|
||||
|
||||
const { default: koaResourceParam } = await import('./koa-resource-param.js');
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const noop = async () => {};
|
||||
|
||||
const endpoint = 'https://logto.io/oidc/auth';
|
||||
|
||||
describe('koaResourceParam() middleware', () => {
|
||||
it('should check and process comma separated resource params in the URL', async () => {
|
||||
const ctx = createMockContext({ url: endpoint + '?resource=foo,bar' });
|
||||
const run = koaResourceParam();
|
||||
|
||||
await run(ctx, noop);
|
||||
|
||||
expect(ctx.request.query).toEqual({
|
||||
resource: ['foo', 'bar'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should also work with both comma separated and single resource params', async () => {
|
||||
const ctx = createMockContext({ url: endpoint + '?resource=foo,bar&resource=baz' });
|
||||
const run = koaResourceParam();
|
||||
|
||||
await run(ctx, noop);
|
||||
|
||||
expect(ctx.request.query).toEqual({
|
||||
resource: ['foo', 'bar', 'baz'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should not affect the URL if no comma separated resource params are found', async () => {
|
||||
const ctx = createMockContext({ url: endpoint + '?resource=foo&resource=bar' });
|
||||
const run = koaResourceParam();
|
||||
|
||||
await run(ctx, noop);
|
||||
|
||||
expect(ctx.request.query).toEqual({
|
||||
resource: ['foo', 'bar'],
|
||||
});
|
||||
});
|
||||
});
|
31
packages/core/src/middleware/koa-resource-param.ts
Normal file
31
packages/core/src/middleware/koa-resource-param.ts
Normal file
|
@ -0,0 +1,31 @@
|
|||
import type { Nullable } from '@silverhand/essentials';
|
||||
import type { MiddlewareType } from 'koa';
|
||||
|
||||
/**
|
||||
* Create a middleware function that checks if the request URL contains comma separated `resource` query parameter.
|
||||
* If yes, split the values and reconstruct the URL with multiple `resource` query parameters.
|
||||
* E.g. `?resource=foo,bar` => `?resource=foo&resource=bar`
|
||||
*/
|
||||
export default function koaResourceParam<StateT, ContextT, ResponseBodyT>(): MiddlewareType<
|
||||
StateT,
|
||||
ContextT,
|
||||
Nullable<ResponseBodyT>
|
||||
> {
|
||||
return async (ctx, next) => {
|
||||
const { query } = ctx.request;
|
||||
const { resource } = query;
|
||||
|
||||
if (!resource) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const resources = Array.isArray(resource) ? resource : [resource];
|
||||
const resourceParams = resources.flatMap((resource) => resource.split(','));
|
||||
|
||||
ctx.request.query = {
|
||||
...query,
|
||||
resource: resourceParams,
|
||||
};
|
||||
return next();
|
||||
};
|
||||
}
|
|
@ -28,6 +28,7 @@ import { type CloudConnectionLibrary } from '#src/libraries/cloud-connection.js'
|
|||
import { type LogtoConfigLibrary } from '#src/libraries/logto-config.js';
|
||||
import koaAuditLog from '#src/middleware/koa-audit-log.js';
|
||||
import koaBodyEtag from '#src/middleware/koa-body-etag.js';
|
||||
import koaResourceParam from '#src/middleware/koa-resource-param.js';
|
||||
import postgresAdapter from '#src/oidc/adapter.js';
|
||||
import {
|
||||
buildLoginPromptUrl,
|
||||
|
@ -377,6 +378,12 @@ export default function initOidc(
|
|||
throw error;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* Check if the request URL contains comma separated `resource` query parameter. If yes, split the values and
|
||||
* reconstruct the URL with multiple `resource` query parameters.
|
||||
* E.g. `?resource=foo,bar` => `?resource=foo&resource=bar`
|
||||
*/
|
||||
oidc.use(koaResourceParam());
|
||||
/**
|
||||
* `oidc-provider` [strictly checks](https://github.com/panva/node-oidc-provider/blob/6a0bcbcd35ed3e6179e81f0ab97a45f5e4e58f48/lib/shared/selective_body.js#L11)
|
||||
* the `content-type` header for further processing.
|
||||
|
|
Loading…
Reference in a new issue