Skip to content

Commit 9ba432b

Browse files
committed
feat: add feature to disable endpoints
1 parent 269abba commit 9ba432b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+633
-319
lines changed

.changeset/silly-crabs-cover.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"elysia-openid-client": patch
3+
---
4+
5+
Add feature to disable endpoints

.changeset/smooth-buckets-heal.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"elysia-openid-client": patch
33
---
44

5-
Remove `scope` option and fix scope to `scoped`
5+
**[BREAKING CHANGE]** Remove `scope` option and fix scope to `scoped`

.changeset/tame-pugs-draw.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"elysia-openid-client": patch
3+
---
4+
5+
**[BREAKING CHANGE]** Fix multiple issuer support

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
[OpenID Connect](https://openid.net/) client (RP, Relying Party) plugin for [ElysiaJS](https://elysiajs.com/), wrapping [openid-client](https://github.com/panva/node-openid-client).
66

7-
**Currently under early development. All specifications are subject to change without notice, including those involving breaking changes.**
7+
**Currently under early development.
8+
All specifications are subject to change without notice, including those involving breaking changes.**
89

910
## Overview
1011

__mock__/const.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -82,31 +82,33 @@ export const mockIdTokenExpiredClaims = {
8282
sub: "mock-sub",
8383
};
8484

85+
export const mockSessionId = "mock-session-id";
86+
8587
export const mockLoginSession: OIDCClientSession = {
86-
sessionId: "mock-session-id",
88+
sessionId: mockSessionId,
8789
codeVerifier: "mock-code-verifier",
8890
state: "mock-state",
8991
nonce: "mock-nonce",
9092
sessionExpiresAt: 5000000000000,
9193
};
9294

9395
export const mockActiveSession: OIDCClientActiveSession = {
94-
sessionId: "mock-session-id",
96+
sessionId: mockSessionId,
9597
idToken: "mock-id-token",
9698
accessToken: "mock-access-token",
9799
refreshToken: "mock-refresh-token",
98100
sessionExpiresAt: 5000000000000,
99101
};
100102

101103
export const mockActiveSessionWithoutRefreshToken: OIDCClientActiveSession = {
102-
sessionId: "mock-session-id",
104+
sessionId: mockSessionId,
103105
idToken: "mock-id-token",
104106
accessToken: "mock-access-token",
105107
sessionExpiresAt: 5000000000000,
106108
};
107109

108110
export const mockActiveSessionWithRealIdToken: OIDCClientActiveSession = {
109-
sessionId: "mock-session-id",
111+
sessionId: mockSessionId,
110112
idToken: mockIdToken,
111113
accessToken: "mock-access-token",
112114
refreshToken: "mock-refresh-token",
@@ -130,13 +132,13 @@ export const mockActiveSessionWithRealIdTokenExpired: OIDCClientActiveSession =
130132
export const mockPostInit = (sid?: string): RequestInit => ({
131133
method: "POST",
132134
headers: {
133-
Cookie: `${defaultCookieSettings.sessionIdName}=${sid || "mock-sid"}`,
135+
Cookie: `${defaultCookieSettings.sessionIdName}=${sid || mockSessionId}`,
134136
},
135137
});
136138

137139
export const mockGetInit = (sid?: string): RequestInit => ({
138140
headers: {
139-
Cookie: `${defaultCookieSettings.sessionIdName}=${sid || "mock-sid"}`,
141+
Cookie: `${defaultCookieSettings.sessionIdName}=${sid || mockSessionId}`,
140142
},
141143
});
142144

@@ -170,8 +172,11 @@ export const mockBaseClient = {
170172
logger: mockLogger,
171173
initialized: true,
172174
client: {},
175+
clients: {},
173176
sessions: mock(),
174177
} as DeepPartial<OidcClient> as OidcClient;
178+
mockBaseClient.clients["https://op.example.com"] = mockBaseClient.client;
179+
mockBaseClient.clients[`http://localhost:${opPort}`] = mockBaseClient.client;
175180

176181
export const mockCookie = {
177182
[defaultCookieSettings.sessionIdName]: {

elysia-openid-client-0.1.10.tgz

25.3 KB
Binary file not shown.

src/const.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const defaultLoggerOptions: Record<string, LoggerOptions> = {
8484
},
8585
};
8686

87-
export const sessionDataTypeBox = t.Object({
87+
export const sessionTypeBox = t.Object({
8888
sessionId: t.String(),
8989
sessionExpiresAt: t.Number(),
9090
idToken: t.String(),

src/endpoints/callbackEndpoint.test.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
mockBaseClient,
66
mockLoginSession,
77
mockResetRecursively,
8+
mockSessionId,
89
rpPort,
910
} from "@mock/const";
1011
import Elysia from "elysia";
@@ -48,17 +49,17 @@ describe("Unit/endpoints/callbackEndpoint", () => {
4849

4950
test.each([
5051
{
51-
sessionId: "mock-sid",
52+
sessionId: mockSessionId,
5253
state: "mock-state",
5354
nonce: "mock-nonce",
5455
},
5556
{
56-
sessionId: "mock-sid",
57+
sessionId: mockSessionId,
5758
codeVerifier: "mock-verifier",
5859
nonce: "mock-nonce",
5960
},
6061
{
61-
sessionId: "mock-sid",
62+
sessionId: mockSessionId,
6263
codeVerifier: "mock-verifier",
6364
state: "mock-state",
6465
},

src/endpoints/callbackEndpoint.ts

+7
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export function callbackEndpoint(this: OidcClient) {
1919
authParams: { redirect_uri },
2020
logger,
2121
} = this;
22+
23+
if (!callbackPath) {
24+
return new Elysia();
25+
}
26+
2227
const callbackCompletedPath = settings.callbackCompletedPath.startsWith("/")
2328
? `${baseUrl}${settings.callbackCompletedPath}`
2429
: settings.callbackCompletedPath;
@@ -64,8 +69,10 @@ export function callbackEndpoint(this: OidcClient) {
6469
}
6570

6671
extendCookieExpiration(this, cookie);
72+
6773
logger?.debug(`Redirect to: ${callbackCompletedPath}`);
6874
set.redirect = callbackCompletedPath;
75+
6976
return;
7077
} catch (e: unknown) {
7178
logger?.warn("endpoints/callback: Throw exception");

src/endpoints/claimsEndpoint.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe("Unit/endpoints/claimsEndpoint", () => {
2222

2323
test("Succeeded", async () => {
2424
const app = new Elysia()
25-
.resolve(() => ({ sessionData: mockActiveSessionWithRealIdToken }))
25+
.resolve(() => ({ session: mockActiveSessionWithRealIdToken }))
2626
.use(endpoint.call(mockBaseClient));
2727
const response = await app
2828
.handle(new Request(`http://localhost${path}`, mockPostInit()))
@@ -36,7 +36,7 @@ describe("Unit/endpoints/claimsEndpoint", () => {
3636
mockBaseClient.fetchSession = mock().mockReturnValue(null);
3737

3838
const app = new Elysia()
39-
.resolve(() => ({ sessionData: null }))
39+
.resolve(() => ({ session: null }))
4040
.use(endpoint.call(mockBaseClient));
4141
const response = await app
4242
.handle(new Request(`http://localhost${path}`, mockPostInit()))

src/endpoints/claimsEndpoint.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { sessionDataTypeBox } from "@/const";
1+
import { sessionTypeBox } from "@/const";
22
import type { OidcClient } from "@/core/OidcClient";
33
import type { OIDCClientActiveSession } from "@/types";
44
import { getClaimsFromIdToken } from "@/utils/getClaimsFromIdToken";
@@ -16,17 +16,20 @@ export function claimsEndpoint(this: OidcClient) {
1616
logger,
1717
} = this;
1818

19+
if (!claimsPath) {
20+
return new Elysia();
21+
}
22+
1923
return new Elysia()
2024
.decorate({
21-
sessionData: sessionDataTypeBox,
25+
session: sessionTypeBox,
2226
})
2327
.all(
2428
claimsPath,
25-
({ set, sessionData }) => {
29+
({ set, session }) => {
2630
logger?.trace("endpoints/claims");
2731

28-
const currentSession =
29-
sessionData as unknown as OIDCClientActiveSession;
32+
const currentSession = session as unknown as OIDCClientActiveSession;
3033

3134
if (!currentSession) {
3235
logger?.warn("Session data does not exist");

src/endpoints/introspectEndpoint.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe("Unit/endpoints/introspectEndpoint", () => {
2222

2323
test("Succeeded", async () => {
2424
const app = new Elysia()
25-
.resolve(() => ({ sessionData: mockActiveSession }))
25+
.resolve(() => ({ session: mockActiveSession }))
2626
.use(endpoint.call(mockBaseClient));
2727
const response = await app.handle(
2828
new Request(`http://localhost${path}`, mockGetInit()),
@@ -36,7 +36,7 @@ describe("Unit/endpoints/introspectEndpoint", () => {
3636

3737
test("Session missing", async () => {
3838
const app = new Elysia()
39-
.resolve(() => ({ sessionData: null }))
39+
.resolve(() => ({ session: null }))
4040
.use(endpoint.call(mockBaseClient));
4141
const response = await app.handle(
4242
new Request(`http://localhost${path}`, mockGetInit()),
@@ -55,7 +55,7 @@ describe("Unit/endpoints/introspectEndpoint", () => {
5555
};
5656

5757
const app = new Elysia()
58-
.resolve(() => ({ sessionData: mockActiveSession }))
58+
.resolve(() => ({ session: mockActiveSession }))
5959
.use(endpoint.call(mockBaseClient));
6060
const response = await app
6161
.handle(new Request(`http://localhost${path}`))

src/endpoints/introspectEndpoint.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { sessionDataTypeBox } from "@/const";
1+
import { sessionTypeBox } from "@/const";
22
import type { OidcClient } from "@/core/OidcClient";
33
import type { OIDCClientActiveSession } from "@/types";
44
import { handleErrorResponse } from "@/utils/handleErrorResponse";
@@ -15,17 +15,20 @@ export function introspectEndpoint(this: OidcClient) {
1515
logger,
1616
} = this;
1717

18+
if (!introspectPath) {
19+
return new Elysia();
20+
}
21+
1822
return new Elysia()
1923
.decorate({
20-
sessionData: sessionDataTypeBox,
24+
session: sessionTypeBox,
2125
})
2226
.all(
2327
introspectPath,
24-
async ({ set, cookie, sessionData }) => {
28+
async ({ set, cookie, session }) => {
2529
logger?.trace("endpoints/introspect");
2630

27-
const currentSession =
28-
sessionData as unknown as OIDCClientActiveSession;
31+
const currentSession = session as unknown as OIDCClientActiveSession;
2932

3033
try {
3134
if (!currentSession) {

src/endpoints/loginEndpoint.test.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { beforeEach, describe, expect, mock, test } from "bun:test";
22
import { defaultSettings } from "@/const";
3-
import { mockBaseClient, mockResetRecursively, opPort } from "@mock/const";
3+
import {
4+
mockBaseClient,
5+
mockResetRecursively,
6+
mockSessionId,
7+
opPort,
8+
} from "@mock/const";
49
import Elysia from "elysia";
510
import setCookie from "set-cookie-parser";
611
import { loginEndpoint } from "./loginEndpoint";
@@ -13,7 +18,7 @@ describe("Unit/endpoints/loginEndpoint", () => {
1318
beforeEach(() => {
1419
mockResetRecursively(mockBaseClient);
1520
mockBaseClient.createSession = mock().mockReturnValue([
16-
"mock-sid",
21+
mockSessionId,
1722
`http://localhost:${opPort}/authorization`,
1823
]);
1924
});
@@ -32,7 +37,7 @@ describe("Unit/endpoints/loginEndpoint", () => {
3237
response.headers.get("set-cookie") as string,
3338
)[0];
3439
expect(cookie.name).toBe("__Host-sid");
35-
expect(cookie.value).toBe("mock-sid");
40+
expect(cookie.value).toBe(mockSessionId);
3641
expect(cookie.path).toBe("/");
3742
expect((cookie.expires as Date) > new Date()).toBeTruthy();
3843
expect(cookie.httpOnly).toBe(true);

src/endpoints/loginEndpoint.ts

+4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export function loginEndpoint(this: OidcClient) {
2222
logger,
2323
} = this;
2424

25+
if (!loginPath) {
26+
return new Elysia();
27+
}
28+
2529
return new Elysia().get(
2630
loginPath,
2731
async ({ cookie, set }) => {

src/endpoints/logoutEndpoint.ts

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ export function logoutEndpoint(this: OidcClient) {
1717
logger,
1818
} = this;
1919

20+
if (!logoutPath) {
21+
return new Elysia();
22+
}
23+
2024
const logoutCompletedUrl = logoutCompletedPath.startsWith("/")
2125
? `${baseUrl}${logoutCompletedPath}`
2226
: logoutCompletedPath;

src/endpoints/refreshEndpoint.ts

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export function refreshEndpoint(this: OidcClient) {
1616
logger,
1717
} = this;
1818

19+
if (!refreshPath) {
20+
return new Elysia();
21+
}
22+
1923
return new Elysia().all(
2024
refreshPath,
2125
async ({ set, cookie }) => {

src/endpoints/resourceEndpoint.ts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { sessionDataTypeBox } from "@/const";
1+
import { sessionTypeBox } from "@/const";
22
import type { OidcClient } from "@/core/OidcClient";
33
import type { OIDCClientActiveSession } from "@/types";
44
import { handleErrorResponse } from "@/utils/handleErrorResponse";
@@ -17,13 +17,17 @@ export function resourceEndpoint(this: OidcClient) {
1717
logger,
1818
} = this;
1919

20+
if (!resourcePath) {
21+
return new Elysia();
22+
}
23+
2024
return new Elysia()
2125
.decorate({
22-
sessionData: sessionDataTypeBox,
26+
session: sessionTypeBox,
2327
})
2428
.get(
2529
resourcePath,
26-
({ query, cookie, set, sessionData }) => {
30+
({ query, cookie, set, session }) => {
2731
logger?.trace("endpoints/resource");
2832

2933
if (!query.url) {
@@ -32,8 +36,7 @@ export function resourceEndpoint(this: OidcClient) {
3236
return;
3337
}
3438

35-
const currentSession =
36-
sessionData as unknown as OIDCClientActiveSession;
39+
const currentSession = session as unknown as OIDCClientActiveSession;
3740

3841
try {
3942
if (!currentSession) {

src/endpoints/revokeEndpoint.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ export function revokeEndpoint(this: OidcClient) {
1414
logger,
1515
} = this;
1616

17+
if (!revokePath) {
18+
return new Elysia();
19+
}
20+
1721
return new Elysia().all(
1822
revokePath,
1923
async ({ set, cookie }) => {
@@ -30,7 +34,7 @@ export function revokeEndpoint(this: OidcClient) {
3034
await this.client.revoke(staleSession.idToken);
3135

3236
const { sessionId } = staleSession;
33-
logger?.debug(`Revoke complete: ${sessionId}`);
37+
logger?.debug(`Revoke completed: ${sessionId.slice(0, 8)}`);
3438
this.deleteSession(sessionId);
3539
// deleteCookie(this, cookie);
3640

src/endpoints/statusEndpoint.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe("Unit/endpoints/statusEndpoint", () => {
2222

2323
test("Succeeded", async () => {
2424
const app = new Elysia()
25-
.resolve(() => ({ sessionData: mockActiveSessionWithRealIdToken }))
25+
.resolve(() => ({ session: mockActiveSessionWithRealIdToken }))
2626
.use(endpoint.call(mockBaseClient));
2727

2828
const response = await app
@@ -37,7 +37,7 @@ describe("Unit/endpoints/statusEndpoint", () => {
3737

3838
test("Session data does not exist", async () => {
3939
const app = new Elysia()
40-
.resolve(() => ({ sessionData: null }))
40+
.resolve(() => ({ session: null }))
4141
.use(endpoint.call(mockBaseClient));
4242
const response = await app
4343
.handle(new Request(`http://localhost${path}`, mockPostInit()))

0 commit comments

Comments
 (0)