@owlmeans/server-oidc-provider 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +848 -0
  3. package/build/.gitkeep +0 -0
  4. package/build/consts.d.ts +3 -0
  5. package/build/consts.d.ts.map +1 -0
  6. package/build/consts.js +3 -0
  7. package/build/consts.js.map +1 -0
  8. package/build/index.d.ts +5 -0
  9. package/build/index.d.ts.map +1 -0
  10. package/build/index.js +4 -0
  11. package/build/index.js.map +1 -0
  12. package/build/middleware.d.ts +3 -0
  13. package/build/middleware.d.ts.map +1 -0
  14. package/build/middleware.js +24 -0
  15. package/build/middleware.js.map +1 -0
  16. package/build/service.d.ts +4 -0
  17. package/build/service.d.ts.map +1 -0
  18. package/build/service.js +78 -0
  19. package/build/service.js.map +1 -0
  20. package/build/types.d.ts +46 -0
  21. package/build/types.d.ts.map +1 -0
  22. package/build/types.js +2 -0
  23. package/build/types.js.map +1 -0
  24. package/build/utils/client.d.ts +4 -0
  25. package/build/utils/client.d.ts.map +1 -0
  26. package/build/utils/client.js +31 -0
  27. package/build/utils/client.js.map +1 -0
  28. package/build/utils/config.d.ts +4 -0
  29. package/build/utils/config.d.ts.map +1 -0
  30. package/build/utils/config.js +39 -0
  31. package/build/utils/config.js.map +1 -0
  32. package/build/utils/index.d.ts +3 -0
  33. package/build/utils/index.d.ts.map +1 -0
  34. package/build/utils/index.js +3 -0
  35. package/build/utils/index.js.map +1 -0
  36. package/package.json +49 -0
  37. package/src/consts.ts +4 -0
  38. package/src/index.ts +5 -0
  39. package/src/middleware.ts +29 -0
  40. package/src/service.ts +103 -0
  41. package/src/types.ts +55 -0
  42. package/src/utils/client.ts +40 -0
  43. package/src/utils/config.ts +43 -0
  44. package/src/utils/index.ts +3 -0
  45. package/tsconfig.json +15 -0
package/build/.gitkeep ADDED
File without changes
@@ -0,0 +1,3 @@
1
+ export declare const DEFAULT_ALIAS = "oidc-provider";
2
+ export declare const OIDC_ACCOUNT_SERVICE = "oidc-account-service";
3
+ //# sourceMappingURL=consts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.d.ts","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa,kBAAkB,CAAA;AAE5C,eAAO,MAAM,oBAAoB,yBAA0B,CAAA"}
@@ -0,0 +1,3 @@
1
+ export const DEFAULT_ALIAS = 'oidc-provider';
2
+ export const OIDC_ACCOUNT_SERVICE = 'oidc-account-service';
3
+ //# sourceMappingURL=consts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consts.js","sourceRoot":"","sources":["../src/consts.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAA;AAE5C,MAAM,CAAC,MAAM,oBAAoB,GAAI,sBAAsB,CAAA"}
@@ -0,0 +1,5 @@
1
+ export type * from './types.js';
2
+ export * from './service.js';
3
+ export * from './consts.js';
4
+ export * from './middleware.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,mBAAmB,YAAY,CAAA;AAC/B,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './service.js';
2
+ export * from './consts.js';
3
+ export * from './middleware.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,cAAc,CAAA;AAC5B,cAAc,aAAa,CAAA;AAC3B,cAAc,iBAAiB,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { Middleware } from '@owlmeans/context';
2
+ export declare const createOidcProviderMiddleware: (web?: string, oidc?: string) => Middleware;
3
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAOnD,eAAO,MAAM,4BAA4B,SAAS,MAAM,8BAqBvD,CAAA"}
@@ -0,0 +1,24 @@
1
+ import { assertContext, MiddlewareStage, MiddlewareType } from '@owlmeans/context';
2
+ import { DEFAULT_ALIAS as WEB_ALIAS } from '@owlmeans/server-api';
3
+ import { DEFAULT_ALIAS } from './consts.js';
4
+ export const createOidcProviderMiddleware = (web = WEB_ALIAS, oidc = DEFAULT_ALIAS) => {
5
+ const middleware = {
6
+ type: MiddlewareType.Context,
7
+ stage: MiddlewareStage.Loading,
8
+ apply: async (ctx) => {
9
+ const context = assertContext(ctx);
10
+ const webService = context.service(web);
11
+ const oidcService = context.service(oidc);
12
+ const marker = `__oidcServiceAdded-${web}-${oidc}`;
13
+ if (!ctx.cfg.records?.find(record => record.id === marker)) {
14
+ await oidcService.update(webService);
15
+ if (ctx.cfg.records == null) {
16
+ ctx.cfg.records = [];
17
+ }
18
+ ctx.cfg.records.push({ id: marker });
19
+ }
20
+ }
21
+ };
22
+ return middleware;
23
+ };
24
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAClF,OAAO,EAAE,aAAa,IAAI,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,MAAc,SAAS,EAAE,IAAI,GAAG,aAAa,EAAE,EAAE;IAC5F,MAAM,UAAU,GAAe;QAC7B,IAAI,EAAE,cAAc,CAAC,OAAO;QAC5B,KAAK,EAAE,eAAe,CAAC,OAAO;QAC9B,KAAK,EAAE,KAAK,EAAC,GAAG,EAAC,EAAE;YACjB,MAAM,OAAO,GAAG,aAAa,CAAkB,GAAyB,CAAY,CAAA;YACpF,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAY,GAAG,CAAC,CAAA;YAClD,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAsB,IAAI,CAAC,CAAA;YAE9D,MAAM,MAAM,GAAG,sBAAsB,GAAG,IAAI,IAAI,EAAE,CAAA;YAClD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC;gBAC3D,MAAM,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;gBACpC,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,EAAE,CAAC;oBAC5B,GAAG,CAAC,GAAG,CAAC,OAAO,GAAG,EAAE,CAAA;gBACtB,CAAC;gBACD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YACtC,CAAC;QACH,CAAC;KACF,CAAA;IAED,OAAO,UAAU,CAAA;AACnB,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { Config, Context, OidcProviderService } from './types.js';
2
+ export declare const createOidcProviderService: (alias?: string) => OidcProviderService;
3
+ export declare const appendOidcProviderService: <C extends Config, T extends Context<C>>(ctx: T, alias?: string) => T;
4
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAA0C,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAS9G,eAAO,MAAM,yBAAyB,WAAW,MAAM,KAAmB,mBA+EzE,CAAA;AAED,eAAO,MAAM,yBAAyB,GAAI,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,OACzE,CAAC,UAAS,MAAM,KACpB,CAOF,CAAA"}
@@ -0,0 +1,78 @@
1
+ import { assertContext, createService } from '@owlmeans/context';
2
+ import { DEFAULT_ALIAS, OIDC_ACCOUNT_SERVICE } from './consts.js';
3
+ import { DEFAULT_PATH, INTERACTION } from '@owlmeans/oidc';
4
+ import Provider from 'oidc-provider';
5
+ import { SEP } from '@owlmeans/route';
6
+ import { makeSecurityHelper } from '@owlmeans/config';
7
+ import { combineConfig } from './utils/config.js';
8
+ let _initializedOidc = undefined;
9
+ export const createOidcProviderService = (alias = DEFAULT_ALIAS) => {
10
+ const service = createService(alias, {
11
+ update: async (api) => {
12
+ const context = assertContext(service.ctx, alias);
13
+ const cfg = context.cfg.oidc;
14
+ const serviceRoute = context.cfg.services[cfg.authService ?? context.cfg.service];
15
+ const helper = makeSecurityHelper(context);
16
+ const url = helper.makeUrl(serviceRoute, cfg.basePath ?? DEFAULT_PATH, { base: true });
17
+ const unsecure = context.cfg.security?.unsecure === false ? false : !url.startsWith('https');
18
+ const oidc = new Provider(url, {
19
+ ...await combineConfig(context, unsecure),
20
+ adapter: cfg.adapterService != null
21
+ ? name => context.service(cfg.adapterService).instance(name)
22
+ : undefined,
23
+ findAccount: async (_, id, _token) => {
24
+ const accountSrv = context.service(cfg.accountService ?? OIDC_ACCOUNT_SERVICE);
25
+ return accountSrv.loadById(context, id);
26
+ },
27
+ interactions: {
28
+ url: async (_, interaction) => {
29
+ const module = context.module(INTERACTION);
30
+ const [uri] = await module.call({ params: { uid: interaction.uid } });
31
+ return uri;
32
+ }
33
+ }
34
+ });
35
+ oidc.proxy = cfg.behindProxy ?? unsecure;
36
+ const base = SEP + (cfg.basePath ?? DEFAULT_PATH);
37
+ await api.server.use(base, oidc.callback());
38
+ oidc.use(async (ctx, next) => {
39
+ await next();
40
+ const csp = ctx.response.headers['content-security-policy'];
41
+ if (csp != null) {
42
+ // @TODO Make it a little bit nicer - preferably using helmet :)
43
+ ctx.response.set('Content-Security-Policy', csp.replace(/form-action 'self'/, 'form-action *'));
44
+ }
45
+ });
46
+ if (context.cfg.debug?.all || context.cfg.debug?.oidc) {
47
+ oidc.use(async (_, next) => {
48
+ await next();
49
+ });
50
+ oidc.on('grant.error', (_, error) => {
51
+ console.warn('GRANT ERROR .......: ');
52
+ console.info(oidc.issuer, _.request.toJSON(), _.body);
53
+ console.error('!!!! GRANT ERROR: ', error);
54
+ });
55
+ oidc.on('server_error', (ctx, error) => {
56
+ console.warn('SERVER ERROR .......: ', Object.getOwnPropertyNames(ctx.oidc));
57
+ console.info(ctx.oidc.grant);
58
+ console.error('!!!! SERVER ERROR: ', error);
59
+ });
60
+ }
61
+ _initializedOidc = service.oidc = oidc;
62
+ },
63
+ instance: () => {
64
+ return service.oidc ?? (service.oidc = _initializedOidc);
65
+ },
66
+ getInteraction: async (id) => {
67
+ return await service.instance().Interaction.find(id) ?? null;
68
+ }
69
+ });
70
+ return service;
71
+ };
72
+ export const appendOidcProviderService = (ctx, alias = DEFAULT_ALIAS) => {
73
+ const service = createOidcProviderService(alias);
74
+ const context = ctx;
75
+ context.registerService(service);
76
+ return context;
77
+ };
78
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { InitializedService } from '@owlmeans/context';
2
+ import type { OidcSharedConfig } from '@owlmeans/oidc';
3
+ import type { ApiServer, ApiServerAppend } from '@owlmeans/server-api';
4
+ import type { ServerConfig, ServerContext } from '@owlmeans/server-context';
5
+ import type { Account, Adapter, ClientMetadata, Configuration, Interaction, Provider } from 'oidc-provider';
6
+ export interface OidcProviderService extends InitializedService {
7
+ oidc: Provider;
8
+ update: (api: ApiServer) => Promise<void>;
9
+ instance: () => Provider;
10
+ getInteraction: (id: string) => Promise<Interaction | null>;
11
+ }
12
+ export interface OidcConfigAppend<Extra extends OidcSharedConfig = OidcSharedConfig> {
13
+ oidc: OidcConfig & Extra;
14
+ }
15
+ export interface OidcConfig extends OidcSharedConfig {
16
+ authService?: string;
17
+ basePath?: string;
18
+ frontBase?: string;
19
+ clients: ClientMetadata[];
20
+ customConfiguration?: Configuration;
21
+ behindProxy?: boolean;
22
+ defaultKeys: {
23
+ RS256: {
24
+ pk: string;
25
+ pub?: string;
26
+ };
27
+ };
28
+ accountService?: string;
29
+ adapterService?: string;
30
+ }
31
+ export interface OidcAccountService extends InitializedService {
32
+ loadById: <C extends Config, T extends Context<C>>(ctx: T, id: string) => Promise<Account | undefined>;
33
+ }
34
+ export interface OidcAdapterService extends InitializedService {
35
+ instance: (name: string) => Adapter;
36
+ }
37
+ export interface Config extends ServerConfig, OidcConfigAppend {
38
+ debug: ServerConfig["debug"] & {
39
+ oidc?: boolean;
40
+ oidcServer?: boolean;
41
+ oidcData?: boolean;
42
+ };
43
+ }
44
+ export interface Context<C extends Config = Config> extends ServerContext<C>, ApiServerAppend {
45
+ }
46
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE3G,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,IAAI,EAAE,QAAQ,CAAA;IAEd,MAAM,EAAE,CAAC,GAAG,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzC,QAAQ,EAAE,MAAM,QAAQ,CAAA;IAExB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAA;CAC5D;AAED,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,gBAAgB,GAAG,gBAAgB;IACjF,IAAI,EAAE,UAAU,GAAG,KAAK,CAAA;CACzB;AAED,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,mBAAmB,CAAC,EAAE,aAAa,CAAA;IACnC,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,WAAW,EAAE;QACX,KAAK,EAAE;YACL,EAAE,EAAE,MAAM,CAAA;YACV,GAAG,CAAC,EAAE,MAAM,CAAA;SACb,CAAA;KACF,CAAA;IACD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,QAAQ,EAAE,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAAA;CACvG;AAED,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAA;CACpC;AAED,MAAM,WAAW,MAAO,SAAQ,YAAY,EAAE,gBAAgB;IAC5D,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG;QAC7B,IAAI,CAAC,EAAE,OAAO,CAAA;QACd,UAAU,CAAC,EAAE,OAAO,CAAA;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAA;KACnB,CAAA;CACF;AAED,MAAM,WAAW,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,aAAa,CAAC,CAAC,CAAC,EACxE,eAAe;CAAI"}
package/build/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { ClientMetadata } from 'oidc-provider';
2
+ import type { Context } from '../types.js';
3
+ export declare const updateClient: (context: Context, client: ClientMetadata) => ClientMetadata;
4
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/utils/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AACnD,OAAO,KAAK,EAAU,OAAO,EAAE,MAAM,aAAa,CAAA;AAKlD,eAAO,MAAM,YAAY,YAAa,OAAO,UAAU,cAAc,KAAG,cAoBvE,CAAA"}
@@ -0,0 +1,31 @@
1
+ import { randomBytes } from '@noble/hashes/utils';
2
+ import { hex } from '@scure/base';
3
+ import { makeSecurityHelper } from '@owlmeans/config';
4
+ import { SEP } from '@owlmeans/route';
5
+ export const updateClient = (context, client) => {
6
+ if (client.client_secret == null) {
7
+ if (!context.cfg.debug.all && !context.cfg.debug.oidc) {
8
+ throw new SyntaxError('Client secret is required');
9
+ }
10
+ client.client_secret = hex.encode(randomBytes(32));
11
+ console.info('\n');
12
+ console.info('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
13
+ console.warn('IT IS EXCEPTIONALY UNSECURE, BUT WE GENEREATED A CLIENT SECRET FOR YOU', client.client_secret);
14
+ console.info('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
15
+ console.info('\n');
16
+ }
17
+ const helper = makeSecurityHelper(context);
18
+ const updateUri = makeUriUpdater(context, helper);
19
+ client.redirect_uris = client.redirect_uris?.map(updateUri) ?? [];
20
+ client.post_logout_redirect_uris = client.post_logout_redirect_uris?.map(updateUri) ?? [];
21
+ return client;
22
+ };
23
+ const makeUriUpdater = (context, helper) => (uri) => {
24
+ if (uri.startsWith('{{')) {
25
+ const [host, ...parts] = uri.split(SEP);
26
+ const service = context.cfg.services[host.slice(2, -2)];
27
+ return helper.makeUrl(service, parts.join(SEP));
28
+ }
29
+ return uri;
30
+ };
31
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/utils/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAGjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAErC,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,OAAgB,EAAE,MAAsB,EAAkB,EAAE;IACvF,IAAI,MAAM,CAAC,aAAa,IAAI,IAAI,EAAE,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACtD,MAAM,IAAI,WAAW,CAAC,2BAA2B,CAAC,CAAA;QACpD,CAAC;QACD,MAAM,CAAC,aAAa,GAAG,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAA;QAElD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClB,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAA;QACtD,OAAO,CAAC,IAAI,CAAC,wEAAwE,EAAE,MAAM,CAAC,aAAa,CAAC,CAAA;QAC5G,OAAO,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAA;QACtD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACpB,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAkB,OAAO,CAAC,CAAA;IAC3D,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;IACjD,MAAM,CAAC,aAAa,GAAG,MAAM,CAAC,aAAa,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAA;IACjE,MAAM,CAAC,yBAAyB,GAAG,MAAM,CAAC,yBAAyB,EAAE,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAA;IAEzF,OAAO,MAAM,CAAA;AACf,CAAC,CAAA;AAED,MAAM,cAAc,GAAG,CAAC,OAAgB,EAAE,MAAsB,EAAE,EAAE,CAAC,CAAC,GAAW,EAAU,EAAE;IAC3F,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEvC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QACvD,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA"}
@@ -0,0 +1,4 @@
1
+ import type { Context } from '../types.js';
2
+ import type { Configuration } from 'oidc-provider';
3
+ export declare const combineConfig: (context: Context, _unsecure: boolean) => Promise<Configuration>;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAIlD,eAAO,MAAM,aAAa,YAAmB,OAAO,aAAa,OAAO,KAAG,OAAO,CAAC,aAAa,CAqC/F,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { updateClient } from './client.js';
2
+ import * as jose from 'jose';
3
+ export const combineConfig = async (context, _unsecure) => {
4
+ const cfg = context.cfg.oidc;
5
+ const configuration = {
6
+ ...cfg.customConfiguration,
7
+ clients: [
8
+ ...cfg.clients,
9
+ ...(cfg.customConfiguration?.clients ?? [])
10
+ ].map(client => updateClient(context, client)),
11
+ claims: {
12
+ email: ['email', 'email_verified', ...cfg.customConfiguration?.claims?.email ?? []],
13
+ profile: [
14
+ 'username', 'family_name', 'given_name', 'locale', 'name', 'nickname', 'preferred_username',
15
+ ...cfg.customConfiguration?.claims?.profile ?? []
16
+ ],
17
+ ...cfg.customConfiguration?.claims,
18
+ },
19
+ scopes: ['openid', 'profile', 'offline_access', ...cfg.customConfiguration?.scopes ?? []],
20
+ features: {
21
+ ...cfg.customConfiguration?.features,
22
+ devInteractions: { enabled: false }
23
+ // devInteractions: {
24
+ // enabled: (
25
+ // (context.cfg.debug.all && context.cfg.debug.oidc !== false)
26
+ // || context.cfg.debug.oidc
27
+ // ) && unsecure,
28
+ // ...cfg.customConfiguration?.features?.devInteractions,
29
+ // },
30
+ },
31
+ jwks: {
32
+ keys: [
33
+ await jose.exportJWK(await jose.importPKCS8(cfg.defaultKeys.RS256.pk, 'RS256'))
34
+ ]
35
+ }
36
+ };
37
+ return configuration;
38
+ };
39
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,IAAI,MAAM,MAAM,CAAA;AAE5B,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAAE,OAAgB,EAAE,SAAkB,EAA0B,EAAE;IAClG,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAA;IAE5B,MAAM,aAAa,GAAkB;QACnC,GAAG,GAAG,CAAC,mBAAmB;QAC1B,OAAO,EAAE;YACP,GAAG,GAAG,CAAC,OAAO;YACd,GAAG,CAAC,GAAG,CAAC,mBAAmB,EAAE,OAAO,IAAI,EAAE,CAAC;SAC5C,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,EAAE;YACN,KAAK,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAC,mBAAmB,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC;YACnF,OAAO,EAAE;gBACP,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,oBAAoB;gBAC3F,GAAG,GAAG,CAAC,mBAAmB,EAAE,MAAM,EAAE,OAAO,IAAI,EAAE;aAClD;YACD,GAAG,GAAG,CAAC,mBAAmB,EAAE,MAAM;SACnC;QACD,MAAM,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,GAAG,CAAC,mBAAmB,EAAE,MAAM,IAAI,EAAE,CAAC;QACzF,QAAQ,EAAE;YACR,GAAG,GAAG,CAAC,mBAAmB,EAAE,QAAQ;YACpC,eAAe,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;YACnC,qBAAqB;YACrB,eAAe;YACf,kEAAkE;YAClE,gCAAgC;YAChC,mBAAmB;YACnB,2DAA2D;YAC3D,KAAK;SACN;QACD,IAAI,EAAE;YACJ,IAAI,EAAE;gBACJ,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;aAChF;SACF;KACF,CAAA;IAED,OAAO,aAAa,CAAA;AACtB,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './config.js';
2
+ export * from './client.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
@@ -0,0 +1,3 @@
1
+ export * from './config.js';
2
+ export * from './client.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@owlmeans/server-oidc-provider",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -b",
7
+ "dev": "sleep 306 && nodemon -e ts,tsx,json --watch src --exec \"tsc -p ./tsconfig.json\"",
8
+ "watch": "tsc -b -w --preserveWatchOutput --pretty"
9
+ },
10
+ "main": "build/index.js",
11
+ "module": "build/index.js",
12
+ "types": "build/index.d.ts",
13
+ "exports": {
14
+ ".": {
15
+ "import": "./build/index.js",
16
+ "require": "./build/index.js",
17
+ "default": "./build/index.js",
18
+ "module": "./build/index.js",
19
+ "types": "./build/index.d.ts"
20
+ }
21
+ },
22
+ "devDependencies": {
23
+ "@types/node": "^22.7.8",
24
+ "@types/oidc-provider": "^8.5.2",
25
+ "nodemon": "^3.1.7",
26
+ "npm-check": "^6.0.1",
27
+ "typescript": "^5.6.3"
28
+ },
29
+ "peerDependencies": {
30
+ "fastify": "*"
31
+ },
32
+ "dependencies": {
33
+ "@noble/hashes": "^1.5.0",
34
+ "@owlmeans/client-module": "^0.1.0",
35
+ "@owlmeans/config": "^0.1.0",
36
+ "@owlmeans/context": "^0.1.0",
37
+ "@owlmeans/oidc": "^0.1.0",
38
+ "@owlmeans/route": "^0.1.0",
39
+ "@owlmeans/server-api": "^0.1.0",
40
+ "@owlmeans/server-context": "^0.1.0",
41
+ "@scure/base": "^1.1.9",
42
+ "jose": "5.9.6",
43
+ "oidc-provider": "8.5.2"
44
+ },
45
+ "private": false,
46
+ "publishConfig": {
47
+ "access": "public"
48
+ }
49
+ }
package/src/consts.ts ADDED
@@ -0,0 +1,4 @@
1
+
2
+ export const DEFAULT_ALIAS = 'oidc-provider'
3
+
4
+ export const OIDC_ACCOUNT_SERVICE = 'oidc-account-service'
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+
2
+ export type * from './types.js'
3
+ export * from './service.js'
4
+ export * from './consts.js'
5
+ export * from './middleware.js'
@@ -0,0 +1,29 @@
1
+ import type { Middleware } from '@owlmeans/context'
2
+ import { assertContext, MiddlewareStage, MiddlewareType } from '@owlmeans/context'
3
+ import { DEFAULT_ALIAS as WEB_ALIAS } from '@owlmeans/server-api'
4
+ import type { ApiServer } from '@owlmeans/server-api'
5
+ import { DEFAULT_ALIAS } from './consts.js'
6
+ import type { Config, Context, OidcProviderService } from './types.js'
7
+
8
+ export const createOidcProviderMiddleware = (web: string = WEB_ALIAS, oidc = DEFAULT_ALIAS) => {
9
+ const middleware: Middleware = {
10
+ type: MiddlewareType.Context,
11
+ stage: MiddlewareStage.Loading,
12
+ apply: async ctx => {
13
+ const context = assertContext<Config, Context>(ctx as unknown as Context) as Context
14
+ const webService = context.service<ApiServer>(web)
15
+ const oidcService = context.service<OidcProviderService>(oidc)
16
+
17
+ const marker = `__oidcServiceAdded-${web}-${oidc}`
18
+ if (!ctx.cfg.records?.find(record => record.id === marker)) {
19
+ await oidcService.update(webService)
20
+ if (ctx.cfg.records == null) {
21
+ ctx.cfg.records = []
22
+ }
23
+ ctx.cfg.records.push({ id: marker })
24
+ }
25
+ }
26
+ }
27
+
28
+ return middleware
29
+ }
package/src/service.ts ADDED
@@ -0,0 +1,103 @@
1
+ import { assertContext, createService } from '@owlmeans/context'
2
+ import { DEFAULT_ALIAS, OIDC_ACCOUNT_SERVICE } from './consts.js'
3
+ import { DEFAULT_PATH, INTERACTION } from '@owlmeans/oidc'
4
+ import type { Config, Context, OidcAccountService, OidcAdapterService, OidcProviderService } from './types.js'
5
+ import Provider from 'oidc-provider'
6
+ import type { BasicRoute } from '@owlmeans/route'
7
+ import type { ClientModule } from '@owlmeans/client-module'
8
+ import { SEP } from '@owlmeans/route'
9
+ import { makeSecurityHelper } from '@owlmeans/config'
10
+ import { combineConfig } from './utils/config.js'
11
+
12
+ let _initializedOidc: Provider | undefined = undefined
13
+ export const createOidcProviderService = (alias: string = DEFAULT_ALIAS): OidcProviderService => {
14
+ const service: OidcProviderService = createService<OidcProviderService>(alias, {
15
+ update: async api => {
16
+ const context = assertContext<Config, Context>(service.ctx as Context, alias)
17
+ const cfg = context.cfg.oidc
18
+
19
+ const serviceRoute = context.cfg.services[cfg.authService ?? context.cfg.service] as BasicRoute
20
+ const helper = makeSecurityHelper<Config, Context>(context)
21
+ const url = helper.makeUrl(serviceRoute, cfg.basePath ?? DEFAULT_PATH, { base: true })
22
+ const unsecure = context.cfg.security?.unsecure === false ? false : !url.startsWith('https')
23
+
24
+ const oidc = new Provider(url, {
25
+ ...await combineConfig(context, unsecure),
26
+
27
+ adapter: cfg.adapterService != null
28
+ ? name => context.service<OidcAdapterService>(cfg.adapterService!).instance(name)
29
+ : undefined,
30
+
31
+ findAccount: async (_, id, _token) => {
32
+ const accountSrv = context.service<OidcAccountService>(
33
+ cfg.accountService ?? OIDC_ACCOUNT_SERVICE
34
+ )
35
+
36
+ return accountSrv.loadById(context, id)
37
+ },
38
+
39
+ interactions: {
40
+ url: async (_, interaction) => {
41
+ const module = context.module<ClientModule>(INTERACTION)
42
+ const [uri] = await module.call<string>({ params: { uid: interaction.uid } })
43
+ return uri
44
+ }
45
+ }
46
+ })
47
+
48
+ oidc.proxy = cfg.behindProxy ?? unsecure
49
+ const base = SEP + (cfg.basePath ?? DEFAULT_PATH)
50
+
51
+ await api.server.use(base, oidc.callback())
52
+ oidc.use(async (ctx, next) => {
53
+ await next()
54
+ const csp = ctx.response.headers['content-security-policy']
55
+ if (csp != null) {
56
+ // @TODO Make it a little bit nicer - preferably using helmet :)
57
+
58
+ ctx.response.set('Content-Security-Policy', csp.replace(/form-action 'self'/, 'form-action *'))
59
+ }
60
+ })
61
+ if (context.cfg.debug?.all || context.cfg.debug?.oidc) {
62
+ oidc.use(async (_, next) => {
63
+ await next()
64
+ })
65
+
66
+ oidc.on('grant.error', (_, error) => {
67
+ console.warn('GRANT ERROR .......: ')
68
+ console.info(oidc.issuer, _.request.toJSON(), _.body)
69
+ console.error('!!!! GRANT ERROR: ', error)
70
+ })
71
+
72
+ oidc.on('server_error', (ctx, error) => {
73
+ console.warn('SERVER ERROR .......: ', Object.getOwnPropertyNames(ctx.oidc))
74
+ console.info((ctx.oidc as any).grant)
75
+ console.error('!!!! SERVER ERROR: ', error)
76
+ })
77
+ }
78
+
79
+ _initializedOidc = service.oidc = oidc
80
+ },
81
+
82
+ instance: () => {
83
+ return service.oidc ?? (service.oidc = _initializedOidc!)
84
+ },
85
+
86
+ getInteraction: async id => {
87
+ return await service.instance().Interaction.find(id) ?? null
88
+ }
89
+ })
90
+
91
+ return service
92
+ }
93
+
94
+ export const appendOidcProviderService = <C extends Config, T extends Context<C>>(
95
+ ctx: T, alias: string = DEFAULT_ALIAS
96
+ ): T => {
97
+ const service = createOidcProviderService(alias)
98
+ const context = ctx as T
99
+
100
+ context.registerService(service)
101
+
102
+ return context
103
+ }
package/src/types.ts ADDED
@@ -0,0 +1,55 @@
1
+ import type { InitializedService } from '@owlmeans/context'
2
+ import type { OidcSharedConfig } from '@owlmeans/oidc'
3
+ import type { ApiServer, ApiServerAppend } from '@owlmeans/server-api'
4
+ import type { ServerConfig, ServerContext } from '@owlmeans/server-context'
5
+ import type { Account, Adapter, ClientMetadata, Configuration, Interaction, Provider } from 'oidc-provider'
6
+
7
+ export interface OidcProviderService extends InitializedService {
8
+ oidc: Provider
9
+
10
+ update: (api: ApiServer) => Promise<void>
11
+
12
+ instance: () => Provider
13
+
14
+ getInteraction: (id: string) => Promise<Interaction | null>
15
+ }
16
+
17
+ export interface OidcConfigAppend<Extra extends OidcSharedConfig = OidcSharedConfig> {
18
+ oidc: OidcConfig & Extra
19
+ }
20
+
21
+ export interface OidcConfig extends OidcSharedConfig {
22
+ authService?: string
23
+ basePath?: string
24
+ frontBase?: string
25
+ clients: ClientMetadata[]
26
+ customConfiguration?: Configuration
27
+ behindProxy?: boolean
28
+ defaultKeys: {
29
+ RS256: {
30
+ pk: string
31
+ pub?: string
32
+ }
33
+ }
34
+ accountService?: string
35
+ adapterService?: string
36
+ }
37
+
38
+ export interface OidcAccountService extends InitializedService {
39
+ loadById: <C extends Config, T extends Context<C>>(ctx: T, id: string) => Promise<Account | undefined>
40
+ }
41
+
42
+ export interface OidcAdapterService extends InitializedService {
43
+ instance: (name: string) => Adapter
44
+ }
45
+
46
+ export interface Config extends ServerConfig, OidcConfigAppend {
47
+ debug: ServerConfig["debug"] & {
48
+ oidc?: boolean
49
+ oidcServer?: boolean
50
+ oidcData?: boolean
51
+ }
52
+ }
53
+
54
+ export interface Context<C extends Config = Config> extends ServerContext<C>
55
+ , ApiServerAppend { }