fix(oidc): migrate OIDC endpoints and internal handlers to use typedserver IRequestContext and update dependencies
This commit is contained in:
@@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-12-22 - 1.14.1 - fix(oidc)
|
||||||
|
migrate OIDC endpoints and internal handlers to use typedserver IRequestContext and update dependencies
|
||||||
|
|
||||||
|
- Updated route handlers in ts/index.ts to pass ctx (IRequestContext) instead of req
|
||||||
|
- Refactored OIDC manager handlers to accept plugins.typedserver.IRequestContext and use ctx.url, ctx.headers, ctx.formData (handleAuthorize, handleToken, handleUserInfo, handleRevoke)
|
||||||
|
- Bumped dependencies to support the new typedserver API: @api.global/typedserver -> ^8.1.0
|
||||||
|
- Other dependency updates: @design.estate/dees-catalog ^3.4.0, @git.zone/tspublish ^1.11.0, @types/node ^25.0.3
|
||||||
|
- Changing public handler method signatures is a breaking API change; recommend a major version bump
|
||||||
|
|
||||||
## 2025-12-16 - 1.14.0 - feat(docs)
|
## 2025-12-16 - 1.14.0 - feat(docs)
|
||||||
add package READMEs and publish metadata; update web package publish order
|
add package READMEs and publish metadata; update web package publish order
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -18,13 +18,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@api.global/typedrequest": "^3.2.5",
|
"@api.global/typedrequest": "^3.2.5",
|
||||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||||
"@api.global/typedserver": "^7.11.1",
|
"@api.global/typedserver": "^8.1.0",
|
||||||
"@api.global/typedsocket": "^4.1.0",
|
"@api.global/typedsocket": "^4.1.0",
|
||||||
"@consent.software/catalog": "^2.0.1",
|
"@consent.software/catalog": "^2.0.1",
|
||||||
"@design.estate/dees-catalog": "^3.3.1",
|
"@design.estate/dees-catalog": "^3.4.0",
|
||||||
"@design.estate/dees-domtools": "^2.3.6",
|
"@design.estate/dees-domtools": "^2.3.6",
|
||||||
"@design.estate/dees-element": "^2.1.3",
|
"@design.estate/dees-element": "^2.1.3",
|
||||||
"@git.zone/tspublish": "^1.10.3",
|
"@git.zone/tspublish": "^1.11.0",
|
||||||
"@push.rocks/lik": "^6.2.2",
|
"@push.rocks/lik": "^6.2.2",
|
||||||
"@push.rocks/qenv": "^6.1.3",
|
"@push.rocks/qenv": "^6.1.3",
|
||||||
"@push.rocks/smartcli": "^4.0.19",
|
"@push.rocks/smartcli": "^4.0.19",
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
"@git.zone/tsrun": "^2.0.1",
|
"@git.zone/tsrun": "^2.0.1",
|
||||||
"@git.zone/tswatch": "^2.3.13",
|
"@git.zone/tswatch": "^2.3.13",
|
||||||
"@push.rocks/projectinfo": "^5.0.1",
|
"@push.rocks/projectinfo": "^5.0.1",
|
||||||
"@types/node": "^24.10.1"
|
"@types/node": "^25.0.3"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|||||||
Generated
+804
-674
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@idp.global/idp.global',
|
name: '@idp.global/idp.global',
|
||||||
version: '1.14.0',
|
version: '1.14.1',
|
||||||
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-12
@@ -28,40 +28,40 @@ export const runCli = async () => {
|
|||||||
typedserver.options.spaFallback = true;
|
typedserver.options.spaFallback = true;
|
||||||
|
|
||||||
// OIDC Discovery endpoint
|
// OIDC Discovery endpoint
|
||||||
typedserver.addRoute('/.well-known/openid-configuration', 'GET', async (req) => {
|
typedserver.addRoute('/.well-known/openid-configuration', 'GET', async (ctx) => {
|
||||||
return new Response(JSON.stringify(reception.oidcManager.getDiscoveryDocument()), {
|
return new Response(JSON.stringify(reception.oidcManager.getDiscoveryDocument()), {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// JWKS endpoint
|
// JWKS endpoint
|
||||||
typedserver.addRoute('/.well-known/jwks.json', 'GET', async (req) => {
|
typedserver.addRoute('/.well-known/jwks.json', 'GET', async (ctx) => {
|
||||||
return new Response(JSON.stringify(reception.oidcManager.getJwks()), {
|
return new Response(JSON.stringify(reception.oidcManager.getJwks()), {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// OAuth Authorization endpoint
|
// OAuth Authorization endpoint
|
||||||
typedserver.addRoute('/oauth/authorize', 'GET', async (req) => {
|
typedserver.addRoute('/oauth/authorize', 'GET', async (ctx) => {
|
||||||
return reception.oidcManager.handleAuthorize(req);
|
return reception.oidcManager.handleAuthorize(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
// OAuth Token endpoint
|
// OAuth Token endpoint
|
||||||
typedserver.addRoute('/oauth/token', 'POST', async (req) => {
|
typedserver.addRoute('/oauth/token', 'POST', async (ctx) => {
|
||||||
return reception.oidcManager.handleToken(req);
|
return reception.oidcManager.handleToken(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
// OAuth UserInfo endpoint (GET and POST)
|
// OAuth UserInfo endpoint (GET and POST)
|
||||||
typedserver.addRoute('/oauth/userinfo', 'GET', async (req) => {
|
typedserver.addRoute('/oauth/userinfo', 'GET', async (ctx) => {
|
||||||
return reception.oidcManager.handleUserInfo(req);
|
return reception.oidcManager.handleUserInfo(ctx);
|
||||||
});
|
});
|
||||||
typedserver.addRoute('/oauth/userinfo', 'POST', async (req) => {
|
typedserver.addRoute('/oauth/userinfo', 'POST', async (ctx) => {
|
||||||
return reception.oidcManager.handleUserInfo(req);
|
return reception.oidcManager.handleUserInfo(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
// OAuth Revocation endpoint
|
// OAuth Revocation endpoint
|
||||||
typedserver.addRoute('/oauth/revoke', 'POST', async (req) => {
|
typedserver.addRoute('/oauth/revoke', 'POST', async (ctx) => {
|
||||||
return reception.oidcManager.handleRevoke(req);
|
return reception.oidcManager.handleRevoke(ctx);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -95,9 +95,8 @@ export class OidcManager {
|
|||||||
/**
|
/**
|
||||||
* Handle the authorization endpoint request
|
* Handle the authorization endpoint request
|
||||||
*/
|
*/
|
||||||
public async handleAuthorize(request: Request): Promise<Response> {
|
public async handleAuthorize(ctx: plugins.typedserver.IRequestContext): Promise<Response> {
|
||||||
const url = new URL(request.url);
|
const params = ctx.url.searchParams;
|
||||||
const params = url.searchParams;
|
|
||||||
|
|
||||||
// Extract authorization request parameters
|
// Extract authorization request parameters
|
||||||
const clientId = params.get('client_id');
|
const clientId = params.get('client_id');
|
||||||
@@ -196,21 +195,21 @@ export class OidcManager {
|
|||||||
/**
|
/**
|
||||||
* Handle the token endpoint request
|
* Handle the token endpoint request
|
||||||
*/
|
*/
|
||||||
public async handleToken(request: Request): Promise<Response> {
|
public async handleToken(ctx: plugins.typedserver.IRequestContext): Promise<Response> {
|
||||||
// Parse form data
|
// Parse form data
|
||||||
const contentType = request.headers.get('content-type');
|
const contentType = ctx.headers.get('content-type');
|
||||||
if (!contentType?.includes('application/x-www-form-urlencoded')) {
|
if (!contentType?.includes('application/x-www-form-urlencoded')) {
|
||||||
return this.tokenErrorResponse('invalid_request', 'Content-Type must be application/x-www-form-urlencoded');
|
return this.tokenErrorResponse('invalid_request', 'Content-Type must be application/x-www-form-urlencoded');
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = await request.formData();
|
const formData = await ctx.formData();
|
||||||
const grantType = formData.get('grant_type') as string;
|
const grantType = formData.get('grant_type') as string;
|
||||||
|
|
||||||
// Extract client credentials from Basic auth or form
|
// Extract client credentials from Basic auth or form
|
||||||
let clientId = formData.get('client_id') as string;
|
let clientId = formData.get('client_id') as string;
|
||||||
let clientSecret = formData.get('client_secret') as string;
|
let clientSecret = formData.get('client_secret') as string;
|
||||||
|
|
||||||
const authHeader = request.headers.get('authorization');
|
const authHeader = ctx.headers.get('authorization');
|
||||||
if (authHeader?.startsWith('Basic ')) {
|
if (authHeader?.startsWith('Basic ')) {
|
||||||
const base64 = authHeader.substring(6);
|
const base64 = authHeader.substring(6);
|
||||||
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
|
const decoded = Buffer.from(base64, 'base64').toString('utf-8');
|
||||||
@@ -469,9 +468,9 @@ export class OidcManager {
|
|||||||
/**
|
/**
|
||||||
* Handle the userinfo endpoint
|
* Handle the userinfo endpoint
|
||||||
*/
|
*/
|
||||||
public async handleUserInfo(request: Request): Promise<Response> {
|
public async handleUserInfo(ctx: plugins.typedserver.IRequestContext): Promise<Response> {
|
||||||
// Get access token from Authorization header
|
// Get access token from Authorization header
|
||||||
const authHeader = request.headers.get('authorization');
|
const authHeader = ctx.headers.get('authorization');
|
||||||
if (!authHeader?.startsWith('Bearer ')) {
|
if (!authHeader?.startsWith('Bearer ')) {
|
||||||
return new Response(JSON.stringify({ error: 'invalid_token' }), {
|
return new Response(JSON.stringify({ error: 'invalid_token' }), {
|
||||||
status: 401,
|
status: 401,
|
||||||
@@ -575,8 +574,8 @@ export class OidcManager {
|
|||||||
/**
|
/**
|
||||||
* Handle the revocation endpoint
|
* Handle the revocation endpoint
|
||||||
*/
|
*/
|
||||||
public async handleRevoke(request: Request): Promise<Response> {
|
public async handleRevoke(ctx: plugins.typedserver.IRequestContext): Promise<Response> {
|
||||||
const formData = await request.formData();
|
const formData = await ctx.formData();
|
||||||
const token = formData.get('token') as string;
|
const token = formData.get('token') as string;
|
||||||
const tokenTypeHint = formData.get('token_type_hint') as string;
|
const tokenTypeHint = formData.get('token_type_hint') as string;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@idp.global/idp.global',
|
name: '@idp.global/idp.global',
|
||||||
version: '1.14.0',
|
version: '1.14.1',
|
||||||
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
description: 'An identity provider software managing user authentications, registrations, and sessions.'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,19 @@ export const cardStyles = css`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base styles for all view components
|
||||||
|
* Provides consistent background and foreground colors
|
||||||
|
*/
|
||||||
|
export const viewBaseStyles = css`
|
||||||
|
:host {
|
||||||
|
display: block;
|
||||||
|
min-height: 100%;
|
||||||
|
background: var(--background);
|
||||||
|
color: var(--foreground);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Typography styles for consistent text hierarchy
|
* Typography styles for consistent text hierarchy
|
||||||
*/
|
*/
|
||||||
@@ -108,10 +121,3 @@ export const navigationStyles = css`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
/**
|
|
||||||
* Legacy export for backwards compatibility
|
|
||||||
*/
|
|
||||||
export default css`
|
|
||||||
${accountDesignTokens}
|
|
||||||
${typographyStyles}
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import { IdpState } from '../../../states/idp.state.js';
|
import { IdpState } from '../../../states/idp.state.js';
|
||||||
import { accountDesignTokens } from '../sharedstyles.js';
|
import * as sharedStyles from '../sharedstyles.js';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
@@ -43,15 +43,9 @@ export class AdminView extends DeesElement {
|
|||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
accountDesignTokens,
|
sharedStyles.accountDesignTokens,
|
||||||
|
sharedStyles.viewBaseStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
min-height: 100%;
|
|
||||||
background: var(--background);
|
|
||||||
color: var(--foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
state,
|
state,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import sharedStyles, { accountDesignTokens, cardStyles, typographyStyles } from '../sharedstyles.js';
|
import * as sharedStyles from '../sharedstyles.js';
|
||||||
import * as accountState from '../../../states/accountstate.js';
|
import * as accountState from '../../../states/accountstate.js';
|
||||||
import { IdpState } from '../../../states/idp.state.js';
|
import { IdpState } from '../../../states/idp.state.js';
|
||||||
|
|
||||||
@@ -45,12 +45,12 @@ export class AppsView extends DeesElement {
|
|||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
accountDesignTokens,
|
sharedStyles.accountDesignTokens,
|
||||||
cardStyles,
|
sharedStyles.viewBaseStyles,
|
||||||
typographyStyles,
|
sharedStyles.cardStyles,
|
||||||
|
sharedStyles.typographyStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
|
||||||
padding: 48px;
|
padding: 48px;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import { accountDesignTokens } from '../sharedstyles.js';
|
import * as sharedStyles from '../sharedstyles.js';
|
||||||
import * as accountStateModule from '../../../states/accountstate.js';
|
import * as accountStateModule from '../../../states/accountstate.js';
|
||||||
import { IdpState } from '../../../states/idp.state.js';
|
import { IdpState } from '../../../states/idp.state.js';
|
||||||
|
|
||||||
@@ -59,15 +59,9 @@ export class BaseView extends DeesElement {
|
|||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
accountDesignTokens,
|
sharedStyles.accountDesignTokens,
|
||||||
|
sharedStyles.viewBaseStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
min-height: 100%;
|
|
||||||
background: var(--background);
|
|
||||||
color: var(--foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import { accountDesignTokens } from '../sharedstyles.js';
|
import * as sharedStyles from '../sharedstyles.js';
|
||||||
import * as accountStateModule from '../../../states/accountstate.js';
|
import * as accountStateModule from '../../../states/accountstate.js';
|
||||||
import { IdpState } from '../../../states/idp.state.js';
|
import { IdpState } from '../../../states/idp.state.js';
|
||||||
|
|
||||||
@@ -41,14 +41,9 @@ export class OrgView extends DeesElement {
|
|||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
accountDesignTokens,
|
sharedStyles.accountDesignTokens,
|
||||||
|
sharedStyles.viewBaseStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
min-height: 100%;
|
|
||||||
background: var(--background);
|
|
||||||
color: var(--foreground);
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import * as plugins from '../../../plugins.js';
|
import * as plugins from '../../../plugins.js';
|
||||||
import sharedStyles from '../sharedstyles.js';
|
import * as sharedStyles from '../sharedstyles.js';
|
||||||
import * as state from '../../../states/accountstate.js';
|
import * as state from '../../../states/accountstate.js';
|
||||||
import { IdpState } from '../../../states/idp.state.js';
|
import { IdpState } from '../../../states/idp.state.js';
|
||||||
|
|
||||||
@@ -23,13 +23,13 @@ declare global {
|
|||||||
export class PaddleSetupView extends DeesElement {
|
export class PaddleSetupView extends DeesElement {
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
sharedStyles,
|
sharedStyles.accountDesignTokens,
|
||||||
|
sharedStyles.viewBaseStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
padding: 48px;
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
margin: auto;
|
margin: 0 auto;
|
||||||
color: ${cssManager.bdTheme('#333', '#fff')};
|
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
css,
|
css,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import sharedStyles, { accountDesignTokens, cardStyles, typographyStyles } from '../sharedstyles.js';
|
import * as sharedStyles from '../sharedstyles.js';
|
||||||
|
|
||||||
import * as state from '../../../states/accountstate.js';
|
import * as state from '../../../states/accountstate.js';
|
||||||
|
|
||||||
@@ -46,12 +46,12 @@ export class SubscriptionView extends DeesElement {
|
|||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
accountDesignTokens,
|
sharedStyles.accountDesignTokens,
|
||||||
cardStyles,
|
sharedStyles.viewBaseStyles,
|
||||||
typographyStyles,
|
sharedStyles.cardStyles,
|
||||||
|
sharedStyles.typographyStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
|
||||||
padding: 48px;
|
padding: 48px;
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
type TemplateResult,
|
type TemplateResult,
|
||||||
} from '@design.estate/dees-element';
|
} from '@design.estate/dees-element';
|
||||||
|
|
||||||
import sharedStyles, { accountDesignTokens, cardStyles, typographyStyles } from '../sharedstyles.js';
|
import * as sharedStyles from '../sharedstyles.js';
|
||||||
import * as accountState from '../../../states/accountstate.js';
|
import * as accountState from '../../../states/accountstate.js';
|
||||||
import { IdpState } from '../../../states/idp.state.js';
|
import { IdpState } from '../../../states/idp.state.js';
|
||||||
import { BulkInviteModal } from '../bulk-invite-modal.js';
|
import { BulkInviteModal } from '../bulk-invite-modal.js';
|
||||||
@@ -83,12 +83,12 @@ export class UsersView extends DeesElement {
|
|||||||
|
|
||||||
public static styles = [
|
public static styles = [
|
||||||
cssManager.defaultStyles,
|
cssManager.defaultStyles,
|
||||||
accountDesignTokens,
|
sharedStyles.accountDesignTokens,
|
||||||
cardStyles,
|
sharedStyles.viewBaseStyles,
|
||||||
typographyStyles,
|
sharedStyles.cardStyles,
|
||||||
|
sharedStyles.typographyStyles,
|
||||||
css`
|
css`
|
||||||
:host {
|
:host {
|
||||||
display: block;
|
|
||||||
padding: 48px;
|
padding: 48px;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
|||||||
Reference in New Issue
Block a user