@shad-claiborne/basic-oidc 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shad Claiborne
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ ```ts
2
+ const issuer = 'https://id.some-idp.com';
3
+ const provider:IdentityProvider = await createIdentityProvider(issuer);
4
+ const clientId = 'client-id';
5
+ const clientSecret = 'client-secret';
6
+ const client:Client = provider.createClient(clientId, clientSecret);
7
+ const codeChallenge = 'test123';
8
+ const authRequest:AuthorizationRequest = client.newAuthorizationRequest()
9
+ .setRedirectUri('https://this-app.com/basic-oidc/callback')
10
+ .setResponseMode('fragment')
11
+ .setResponseType('code id_token')
12
+ .setScope(['email', 'profile'])
13
+ .setCodeChallenge(codeChallenge)
14
+ .setState('data');
15
+ const authURL = authRequest.toURL();
16
+ const window.location.replace(authURL.href);
17
+ // IdP redirects back to https://this-app.com/basic-oidc/callback -
18
+ // i.e. A user has granted us authorization
19
+ const authResponseParams = new URLSearchParams(window.location.hash.substring(1));
20
+ const authResponse = Object.fromEntries(authResponseParams) as AuthorizationResponse;
21
+ const tokenSet:TokenSet = await client.requestAccess(authResponse, codeChallenge);
22
+ const id:Identity = await provider.getIdentity(client, tokenSet);
23
+ // await client.revokeAccess(tokenSet);
24
+ ```
@@ -0,0 +1,279 @@
1
+ export interface IdentityProviderConfiguration {
2
+ issuer: string;
3
+ authorization_endpoint: string;
4
+ token_endpoint: string;
5
+ userinfo_endpoint: string;
6
+ registration_endpoint: string;
7
+ jwks_uri: string;
8
+ response_types_supported: string[];
9
+ response_modes_supported: string[];
10
+ grant_types_supported: string[];
11
+ subject_types_supported: string[];
12
+ id_token_signing_alg_values_supported: string[];
13
+ scopes_supported: string[];
14
+ token_endpoint_auth_methods_supported: string[];
15
+ claims_supported: string[];
16
+ code_challenge_methods_supported: string[];
17
+ introspection_endpoint: string;
18
+ introspection_endpoint_auth_methods_supported: string[];
19
+ revocation_endpoint: string;
20
+ revocation_endpoint_auth_methods_supported: string[];
21
+ end_session_endpoint: string;
22
+ request_parameter_supported: boolean;
23
+ request_object_signing_alg_values_supported: string[];
24
+ device_authorization_endpoint: string;
25
+ pushed_authorization_request_endpoint: string;
26
+ backchannel_token_delivery_modes_supported: string[];
27
+ backchannel_authentication_request_signing_alg_values_supported: string[];
28
+ dpop_signing_alg_values_supported: string[];
29
+ }
30
+ export interface AuthorizationResponse {
31
+ code?: string;
32
+ id_token?: string;
33
+ state?: string;
34
+ }
35
+ export interface TokenSet {
36
+ token_type: string;
37
+ access_token: string;
38
+ expires_in: number;
39
+ refresh_token: string;
40
+ id_token?: string;
41
+ }
42
+ export interface Identity {
43
+ sub: string;
44
+ name?: string;
45
+ email?: string;
46
+ }
47
+ /**
48
+ * class AuthorizationRequest
49
+ */
50
+ export declare class AuthorizationRequest {
51
+ private client;
52
+ private responseType;
53
+ private responseMode;
54
+ private redirectUri;
55
+ private scope;
56
+ private state;
57
+ private codeChallenge;
58
+ private codeChallengeMethod;
59
+ /**
60
+ * constructor
61
+ * @param client Client
62
+ */
63
+ constructor(client: Client);
64
+ /**
65
+ * setRedirectUri
66
+ * @param uri string
67
+ */
68
+ setRedirectUri(uri: string): AuthorizationRequest;
69
+ /**
70
+ * setState
71
+ * @param state string
72
+ */
73
+ setState(state: string): AuthorizationRequest;
74
+ /**
75
+ * setResponseMode
76
+ * @param mode string
77
+ */
78
+ setResponseMode(mode: string): AuthorizationRequest;
79
+ /**
80
+ * setResponseType
81
+ * @param type string[]
82
+ */
83
+ setResponseType(type: string): AuthorizationRequest;
84
+ /**
85
+ * setScope
86
+ * @param scope string[]
87
+ */
88
+ setScope(scope: string[]): AuthorizationRequest;
89
+ /**
90
+ * setCodeChallenge
91
+ * @param challenge string
92
+ * @param method string
93
+ */
94
+ setCodeChallenge(challenge: string, method?: string): AuthorizationRequest;
95
+ /**
96
+ * toURLSearchParams
97
+ * @returns URLSearchParams
98
+ */
99
+ toURLSearchParams(): URLSearchParams;
100
+ /**
101
+ * toURL
102
+ * @returns URL
103
+ */
104
+ toURL(): URL;
105
+ }
106
+ /**
107
+ * class TokenRequest
108
+ */
109
+ export declare class TokenRequest {
110
+ private client;
111
+ private code;
112
+ private codeVerifier;
113
+ private redirectUri;
114
+ private grantType;
115
+ private refreshToken;
116
+ /**
117
+ * constructor
118
+ * @param client Client
119
+ */
120
+ constructor(client: Client);
121
+ /**
122
+ * setCode
123
+ * @param code string
124
+ */
125
+ setCode(code: string): TokenRequest;
126
+ /**
127
+ * setRedirectUri
128
+ * @param uri string
129
+ */
130
+ setRedirectUri(uri: string): TokenRequest;
131
+ /**
132
+ * setCodeVerifier
133
+ * @param verifier string
134
+ */
135
+ setCodeVerifier(verifier: string): TokenRequest;
136
+ /**
137
+ * setGrantType
138
+ * @param type string
139
+ */
140
+ setGrantType(type: string): TokenRequest;
141
+ /**
142
+ * setRefreshToken
143
+ * @param token string
144
+ */
145
+ setRefreshToken(token: string): TokenRequest;
146
+ /**
147
+ * toURLSearchParams
148
+ * @returns URLSearchParams
149
+ */
150
+ toURLSearchParams(): URLSearchParams;
151
+ }
152
+ /**
153
+ * class IdentityProvider
154
+ */
155
+ export declare class IdentityProvider {
156
+ private config;
157
+ /**
158
+ * constructor
159
+ * @param config IdentityProviderConfiguration
160
+ */
161
+ constructor(config: IdentityProviderConfiguration);
162
+ /**
163
+ * getAuthorizationEndpoint
164
+ * @returns string
165
+ */
166
+ getAuthorizationEndpoint(): string;
167
+ /**
168
+ * getTokenEndpoint
169
+ * @returns string
170
+ */
171
+ getTokenEndpoint(): string;
172
+ /**
173
+ * getUserinfoEndpoint
174
+ * @returns string
175
+ */
176
+ getUserinfoEndpoint(): string;
177
+ /**
178
+ * getRevocationEndpoint
179
+ * @returns string
180
+ */
181
+ getRevocationEndpoint(): string;
182
+ /**
183
+ * isResponseModeSupported
184
+ * @param mode string
185
+ * @returns boolean
186
+ */
187
+ isResponseModeSupported(mode: string): boolean;
188
+ /**
189
+ * isResponseTypeSupported
190
+ * @param type string[]
191
+ * @returns boolean
192
+ */
193
+ isResponseTypeSupported(type: string): boolean;
194
+ /**
195
+ * isScopeSupported
196
+ * @param scope string[]
197
+ * @returns boolean
198
+ */
199
+ isScopeSupported(scope: string[]): boolean;
200
+ /**
201
+ * isChallengeMethodSupported
202
+ * @param method string
203
+ * @returns boolean
204
+ */
205
+ isChallengeMethodSupported(method: string): boolean;
206
+ /**
207
+ * isGrantTypeSupported
208
+ * @param method string
209
+ * @returns boolean
210
+ */
211
+ isGrantTypeSupported(type: string): boolean;
212
+ /**
213
+ * createClient
214
+ * @returns Client
215
+ */
216
+ createClient(id: string, secret: string): Client;
217
+ /**
218
+ * getIdentity
219
+ * @param client Client
220
+ * @param tokenSet TokenSet
221
+ * @returns Promise<Identity | null>
222
+ */
223
+ getIdentity(client: Client, tokenSet: TokenSet): Promise<Identity | null>;
224
+ }
225
+ /**
226
+ * class Client
227
+ */
228
+ export declare class Client {
229
+ private provider;
230
+ private clientId;
231
+ private clientSecret;
232
+ /**
233
+ * constructor
234
+ * @param provider IdentityProvider
235
+ * @param id string
236
+ * @param secret string
237
+ */
238
+ constructor(provider: IdentityProvider, id: string, secret: string);
239
+ /**
240
+ * getProvider
241
+ * @returns IdentityProvider
242
+ */
243
+ getProvider(): IdentityProvider;
244
+ /**
245
+ * getClientId
246
+ * @returns string
247
+ */
248
+ getClientId(): string;
249
+ /**
250
+ * getClientSecret
251
+ * @returns string
252
+ */
253
+ getClientSecret(): string;
254
+ /**
255
+ * newAuthorizationRequest
256
+ * @returns AuthorizationRequest
257
+ */
258
+ newAuthorizationRequest(): AuthorizationRequest;
259
+ /**
260
+ * requestAccess
261
+ * @param authResponse AuthorizationResponse
262
+ * @param codeVerifier string
263
+ * @returns Promise<TokenSet>
264
+ */
265
+ requestAccess(authResponse: AuthorizationResponse, codeVerifier?: string): Promise<TokenSet>;
266
+ /**
267
+ * refreshAccess
268
+ * @param tokenSet TokenSet
269
+ * @returns Promise<TokenSet>
270
+ */
271
+ refreshAccess(tokenSet: TokenSet): Promise<TokenSet>;
272
+ /**
273
+ * revokeAccess
274
+ * @param tokenSet TokenSet
275
+ * @returns Promise<void>
276
+ */
277
+ revokeAccess(tokenSet: TokenSet): Promise<void>;
278
+ }
279
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,478 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Client = exports.IdentityProvider = exports.TokenRequest = exports.AuthorizationRequest = void 0;
7
+ const sha256_1 = __importDefault(require("crypto-js/sha256"));
8
+ const enc_base64_1 = __importDefault(require("crypto-js/enc-base64"));
9
+ const enc_utf8_1 = __importDefault(require("crypto-js/enc-utf8"));
10
+ const enc_base64url_1 = __importDefault(require("crypto-js/enc-base64url"));
11
+ const axios_1 = __importDefault(require("axios"));
12
+ const jose_1 = require("jose");
13
+ /**
14
+ * class AuthorizationRequest
15
+ */
16
+ class AuthorizationRequest {
17
+ client;
18
+ responseType;
19
+ responseMode;
20
+ redirectUri;
21
+ scope;
22
+ state;
23
+ codeChallenge;
24
+ codeChallengeMethod;
25
+ /**
26
+ * constructor
27
+ * @param client Client
28
+ */
29
+ constructor(client) {
30
+ this.client = client;
31
+ }
32
+ /**
33
+ * setRedirectUri
34
+ * @param uri string
35
+ */
36
+ setRedirectUri(uri) {
37
+ this.redirectUri = uri;
38
+ return this;
39
+ }
40
+ /**
41
+ * setState
42
+ * @param state string
43
+ */
44
+ setState(state) {
45
+ this.state = state;
46
+ return this;
47
+ }
48
+ /**
49
+ * setResponseMode
50
+ * @param mode string
51
+ */
52
+ setResponseMode(mode) {
53
+ if (this.client.getProvider().isResponseModeSupported(mode)) {
54
+ this.responseMode = mode;
55
+ }
56
+ else
57
+ throw new Error('invalid or unsupported response mode');
58
+ return this;
59
+ }
60
+ /**
61
+ * setResponseType
62
+ * @param type string[]
63
+ */
64
+ setResponseType(type) {
65
+ if (this.client.getProvider().isResponseTypeSupported(type)) {
66
+ this.responseType = type;
67
+ }
68
+ else
69
+ throw new Error('invalid or unsupported response type');
70
+ return this;
71
+ }
72
+ /**
73
+ * setScope
74
+ * @param scope string[]
75
+ */
76
+ setScope(scope) {
77
+ if (this.client.getProvider().isScopeSupported(scope)) {
78
+ this.scope = ['openid', ...scope];
79
+ }
80
+ else
81
+ throw new Error('invalid or unsupported scope');
82
+ return this;
83
+ }
84
+ /**
85
+ * setCodeChallenge
86
+ * @param challenge string
87
+ * @param method string
88
+ */
89
+ setCodeChallenge(challenge, method = 'S256') {
90
+ if (this.client.getProvider().isChallengeMethodSupported(method)) {
91
+ if (method === 'plain') {
92
+ this.codeChallenge = challenge;
93
+ }
94
+ else if (method === 'S256') {
95
+ this.codeChallenge = enc_base64url_1.default.stringify((0, sha256_1.default)(challenge));
96
+ }
97
+ else
98
+ throw new Error('code challenge method not yet implemented');
99
+ this.codeChallengeMethod = method;
100
+ }
101
+ else
102
+ throw new Error('invalid or unsupported code challenge method');
103
+ return this;
104
+ }
105
+ /**
106
+ * toURLSearchParams
107
+ * @returns URLSearchParams
108
+ */
109
+ toURLSearchParams() {
110
+ const params = new URLSearchParams();
111
+ params.append('client_id', this.client.getClientId());
112
+ if (this.responseType === undefined)
113
+ throw new Error('response type is required');
114
+ params.append('response_type', this.responseType);
115
+ if (this.responseMode)
116
+ params.append('response_mode', this.responseMode);
117
+ if (this.redirectUri)
118
+ params.append('redirect_uri', this.redirectUri);
119
+ if (this.scope === undefined)
120
+ throw new Error('scope is required');
121
+ params.append('scope', this.scope.join(' '));
122
+ if (this.state)
123
+ params.append('state', this.state);
124
+ const isCodeResponseTypeIncluded = this.responseType.includes('code');
125
+ if (this.codeChallenge === undefined) {
126
+ if (isCodeResponseTypeIncluded)
127
+ throw new Error("code challenge required for 'code' response type");
128
+ }
129
+ else
130
+ params.append('code_challenge', this.codeChallenge);
131
+ if (this.codeChallengeMethod === undefined) {
132
+ if (isCodeResponseTypeIncluded)
133
+ throw new Error("code challenge method required for 'code' response type");
134
+ }
135
+ else
136
+ params.append('code_challenge_method', this.codeChallengeMethod);
137
+ return params;
138
+ }
139
+ /**
140
+ * toURL
141
+ * @returns URL
142
+ */
143
+ toURL() {
144
+ const endpointUrl = new URL(this.client.getProvider().getAuthorizationEndpoint());
145
+ endpointUrl.search = this.toURLSearchParams().toString();
146
+ return endpointUrl;
147
+ }
148
+ }
149
+ exports.AuthorizationRequest = AuthorizationRequest;
150
+ /**
151
+ * class TokenRequest
152
+ */
153
+ class TokenRequest {
154
+ client;
155
+ code;
156
+ codeVerifier;
157
+ redirectUri;
158
+ grantType;
159
+ refreshToken;
160
+ /**
161
+ * constructor
162
+ * @param client Client
163
+ */
164
+ constructor(client) {
165
+ this.client = client;
166
+ }
167
+ /**
168
+ * setCode
169
+ * @param code string
170
+ */
171
+ setCode(code) {
172
+ this.code = code;
173
+ return this;
174
+ }
175
+ /**
176
+ * setRedirectUri
177
+ * @param uri string
178
+ */
179
+ setRedirectUri(uri) {
180
+ this.redirectUri = uri;
181
+ return this;
182
+ }
183
+ /**
184
+ * setCodeVerifier
185
+ * @param verifier string
186
+ */
187
+ setCodeVerifier(verifier) {
188
+ this.codeVerifier = verifier;
189
+ return this;
190
+ }
191
+ /**
192
+ * setGrantType
193
+ * @param type string
194
+ */
195
+ setGrantType(type) {
196
+ if (this.client.getProvider().isGrantTypeSupported(type)) {
197
+ this.grantType = type;
198
+ }
199
+ else
200
+ throw new Error('grant type not supported');
201
+ return this;
202
+ }
203
+ /**
204
+ * setRefreshToken
205
+ * @param token string
206
+ */
207
+ setRefreshToken(token) {
208
+ this.refreshToken = token;
209
+ return this;
210
+ }
211
+ /**
212
+ * toURLSearchParams
213
+ * @returns URLSearchParams
214
+ */
215
+ toURLSearchParams() {
216
+ const params = new URLSearchParams();
217
+ params.append('client_id', this.client.getClientId());
218
+ params.append('client_secret', this.client.getClientSecret());
219
+ if (this.grantType === undefined)
220
+ throw new Error('grant type is required');
221
+ params.append('grant_type', this.grantType);
222
+ if (this.grantType === 'authorization_code') {
223
+ if (this.code === undefined)
224
+ throw new Error('code is required for authorization code flow');
225
+ params.append('code', this.code);
226
+ if (this.codeVerifier)
227
+ params.append('code_verifier', this.codeVerifier);
228
+ if (this.redirectUri)
229
+ params.append('redirect_uri', this.redirectUri);
230
+ }
231
+ else if (this.grantType === 'refresh_token') {
232
+ if (this.refreshToken === undefined)
233
+ throw new Error('refresh token required for grant type');
234
+ params.append('refresh_token', this.refreshToken);
235
+ }
236
+ return params;
237
+ }
238
+ }
239
+ exports.TokenRequest = TokenRequest;
240
+ /**
241
+ * class IdentityProvider
242
+ */
243
+ class IdentityProvider {
244
+ config;
245
+ /**
246
+ * constructor
247
+ * @param config IdentityProviderConfiguration
248
+ */
249
+ constructor(config) {
250
+ this.config = config;
251
+ }
252
+ /**
253
+ * getAuthorizationEndpoint
254
+ * @returns string
255
+ */
256
+ getAuthorizationEndpoint() {
257
+ return this.config.authorization_endpoint;
258
+ }
259
+ /**
260
+ * getTokenEndpoint
261
+ * @returns string
262
+ */
263
+ getTokenEndpoint() {
264
+ return this.config.token_endpoint;
265
+ }
266
+ /**
267
+ * getUserinfoEndpoint
268
+ * @returns string
269
+ */
270
+ getUserinfoEndpoint() {
271
+ return this.config.userinfo_endpoint;
272
+ }
273
+ /**
274
+ * getRevocationEndpoint
275
+ * @returns string
276
+ */
277
+ getRevocationEndpoint() {
278
+ return this.config.revocation_endpoint;
279
+ }
280
+ /**
281
+ * isResponseModeSupported
282
+ * @param mode string
283
+ * @returns boolean
284
+ */
285
+ isResponseModeSupported(mode) {
286
+ return this.config.response_modes_supported.includes(mode);
287
+ }
288
+ /**
289
+ * isResponseTypeSupported
290
+ * @param type string[]
291
+ * @returns boolean
292
+ */
293
+ isResponseTypeSupported(type) {
294
+ return this.config.response_types_supported.includes(type);
295
+ }
296
+ /**
297
+ * isScopeSupported
298
+ * @param scope string[]
299
+ * @returns boolean
300
+ */
301
+ isScopeSupported(scope) {
302
+ return scope.length === scope.filter(s => this.config.scopes_supported.includes(s)).length;
303
+ }
304
+ /**
305
+ * isChallengeMethodSupported
306
+ * @param method string
307
+ * @returns boolean
308
+ */
309
+ isChallengeMethodSupported(method) {
310
+ return this.config.code_challenge_methods_supported.includes(method);
311
+ }
312
+ /**
313
+ * isGrantTypeSupported
314
+ * @param method string
315
+ * @returns boolean
316
+ */
317
+ isGrantTypeSupported(type) {
318
+ return this.config.grant_types_supported.includes(type);
319
+ }
320
+ /**
321
+ * createClient
322
+ * @returns Client
323
+ */
324
+ createClient(id, secret) {
325
+ const client = new Client(this, id, secret);
326
+ return client;
327
+ }
328
+ /**
329
+ * getIdentity
330
+ * @param client Client
331
+ * @param tokenSet TokenSet
332
+ * @returns Promise<Identity | null>
333
+ */
334
+ async getIdentity(client, tokenSet) {
335
+ let id = null;
336
+ if (tokenSet.id_token) {
337
+ const jwks = (0, jose_1.createRemoteJWKSet)(new URL(this.config.jwks_uri));
338
+ const { payload } = await (0, jose_1.jwtVerify)(tokenSet.id_token, jwks, { issuer: this.config.issuer });
339
+ id = payload;
340
+ }
341
+ else {
342
+ const api = new IdentityProviderApi(this, tokenSet);
343
+ id = await api.fetchUserinfo();
344
+ }
345
+ return id;
346
+ }
347
+ }
348
+ exports.IdentityProvider = IdentityProvider;
349
+ /**
350
+ * class IdentityProviderApi
351
+ */
352
+ class IdentityProviderApi {
353
+ provider;
354
+ tokenSet;
355
+ /**
356
+ * constructor
357
+ * @param provider IdentityProvider
358
+ * @param client Client
359
+ */
360
+ constructor(provider, tokenSet) {
361
+ this.provider = provider;
362
+ this.tokenSet = tokenSet;
363
+ }
364
+ /**
365
+ * setTokenSet
366
+ * @param tokenSet TokenSet
367
+ */
368
+ setTokenSet(tokenSet) {
369
+ this.tokenSet = tokenSet;
370
+ }
371
+ /**
372
+ * fetchUserinfo
373
+ * @returns Promise<Identity>
374
+ */
375
+ async fetchUserinfo() {
376
+ const res = await axios_1.default.get(this.provider.getUserinfoEndpoint(), {
377
+ headers: {
378
+ 'Authorization': `Bearer ${this.tokenSet.access_token}`
379
+ }
380
+ });
381
+ return res.data;
382
+ }
383
+ }
384
+ /**
385
+ * class Client
386
+ */
387
+ class Client {
388
+ provider;
389
+ clientId;
390
+ clientSecret;
391
+ /**
392
+ * constructor
393
+ * @param provider IdentityProvider
394
+ * @param id string
395
+ * @param secret string
396
+ */
397
+ constructor(provider, id, secret) {
398
+ this.provider = provider;
399
+ this.clientId = id;
400
+ this.clientSecret = secret;
401
+ }
402
+ /**
403
+ * getProvider
404
+ * @returns IdentityProvider
405
+ */
406
+ getProvider() {
407
+ return this.provider;
408
+ }
409
+ /**
410
+ * getClientId
411
+ * @returns string
412
+ */
413
+ getClientId() {
414
+ return this.clientId;
415
+ }
416
+ /**
417
+ * getClientSecret
418
+ * @returns string
419
+ */
420
+ getClientSecret() {
421
+ return this.clientSecret;
422
+ }
423
+ /**
424
+ * newAuthorizationRequest
425
+ * @returns AuthorizationRequest
426
+ */
427
+ newAuthorizationRequest() {
428
+ const req = new AuthorizationRequest(this);
429
+ return req;
430
+ }
431
+ /**
432
+ * requestAccess
433
+ * @param authResponse AuthorizationResponse
434
+ * @param codeVerifier string
435
+ * @returns Promise<TokenSet>
436
+ */
437
+ async requestAccess(authResponse, codeVerifier) {
438
+ const tokenRequest = new TokenRequest(this);
439
+ if (authResponse.code === undefined)
440
+ throw new Error('authorization response did not include a code');
441
+ tokenRequest.setCode(authResponse.code)
442
+ .setGrantType('authorization_code');
443
+ if (codeVerifier)
444
+ tokenRequest.setCodeVerifier(codeVerifier);
445
+ const res = await axios_1.default.post(this.provider.getTokenEndpoint(), tokenRequest.toURLSearchParams());
446
+ return res.data;
447
+ }
448
+ /**
449
+ * refreshAccess
450
+ * @param tokenSet TokenSet
451
+ * @returns Promise<TokenSet>
452
+ */
453
+ async refreshAccess(tokenSet) {
454
+ const tokenRequest = new TokenRequest(this)
455
+ .setRefreshToken(tokenSet.refresh_token)
456
+ .setGrantType('refresh_token');
457
+ const res = await axios_1.default.post(this.provider.getTokenEndpoint(), tokenRequest.toURLSearchParams());
458
+ return res.data;
459
+ }
460
+ /**
461
+ * revokeAccess
462
+ * @param tokenSet TokenSet
463
+ * @returns Promise<void>
464
+ */
465
+ async revokeAccess(tokenSet) {
466
+ const credentials = enc_base64_1.default.stringify(enc_utf8_1.default.parse(`${this.clientId}:${this.clientSecret}`));
467
+ const params = new URLSearchParams();
468
+ params.append('token', tokenSet.access_token);
469
+ params.append('token_type_hint', 'access_token');
470
+ await axios_1.default.post(this.provider.getRevocationEndpoint(), params, {
471
+ headers: {
472
+ 'Authorization': `Basic ${credentials}`
473
+ }
474
+ });
475
+ }
476
+ }
477
+ exports.Client = Client;
478
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,8 @@
1
+ import { IdentityProvider } from "./identity-provider";
2
+ /**
3
+ * createIdentityProvider
4
+ * @param issuer string
5
+ * @returns IdentityProvider
6
+ */
7
+ export declare const createIdentityProvider: (issuer: string) => Promise<IdentityProvider>;
8
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createIdentityProvider = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const identity_provider_1 = require("./identity-provider");
9
+ /**
10
+ * createIdentityProvider
11
+ * @param issuer string
12
+ * @returns IdentityProvider
13
+ */
14
+ const createIdentityProvider = async (issuer) => {
15
+ const discoveryUrl = `${issuer}/.well-known/openid-configuration`;
16
+ const res = await axios_1.default.get(discoveryUrl);
17
+ const config = res.data;
18
+ const provider = new identity_provider_1.IdentityProvider(config);
19
+ return provider;
20
+ };
21
+ exports.createIdentityProvider = createIdentityProvider;
22
+ //# sourceMappingURL=index.js.map
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@shad-claiborne/basic-oidc",
3
+ "version": "1.0.0",
4
+ "description": "Simple OpenID Connect",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "import": "./dist/index.js",
10
+ "types": "./dist/index.d.ts"
11
+ },
12
+ "./identity-provider": {
13
+ "import": "./dist/identity-provider/index.js",
14
+ "types": "./dist/identity-provider/index.d.ts"
15
+ },
16
+ "./package.json": "./package.json"
17
+ },
18
+ "files": [
19
+ "dist/**/*.js",
20
+ "dist/**/*.d.ts"
21
+ ],
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "test": "vitest"
25
+ },
26
+ "keywords": [
27
+ "openid",
28
+ "oauth"
29
+ ],
30
+ "author": "Shad Claiborne <me@shadclaiborne.com>",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/shad-claiborne/basic-oidc.git"
35
+ },
36
+ "devDependencies": {
37
+ "@types/axios": "^0.9.36",
38
+ "@types/crypto-js": "^4.2.2",
39
+ "@types/node": "^25.0.6",
40
+ "@types/node-jose": "^1.1.13",
41
+ "msw": "^2.12.7",
42
+ "node-jose": "^2.2.0",
43
+ "typescript": "^5.9.3",
44
+ "vitest": "^4.0.17"
45
+ },
46
+ "dependencies": {
47
+ "axios": "^1.13.2",
48
+ "crypto-js": "^4.2.0",
49
+ "jose": "^6.1.3"
50
+ }
51
+ }