@draftlab/auth 0.8.0 → 0.9.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/dist/client.mjs CHANGED
@@ -201,7 +201,10 @@ const createClient = (input) => {
201
201
  },
202
202
  async verify(subjects, token, options) {
203
203
  try {
204
- const jwtResult = await jwtVerify(token, await getJWKS(), { issuer });
204
+ const jwtResult = await jwtVerify(token, await getJWKS(), {
205
+ issuer: options?.issuer ?? issuer,
206
+ ...options?.audience && { audience: options.audience }
207
+ });
205
208
  const validated = await subjects[jwtResult.payload.type]?.["~standard"].validate(jwtResult.payload.properties);
206
209
  if (!validated?.issues && jwtResult.payload.mode === "access") return {
207
210
  success: true,
package/dist/core.d.mts CHANGED
@@ -6,6 +6,7 @@ import { StorageAdapter } from "./storage/storage.mjs";
6
6
  import { Plugin } from "./plugin/types.mjs";
7
7
  import { Provider } from "./provider/provider.mjs";
8
8
  import { Theme } from "./themes/theme.mjs";
9
+ import { AuthorizationState } from "./types.mjs";
9
10
  import { Router } from "@draftlab/auth-router";
10
11
 
11
12
  //#region src/core.d.ts
@@ -27,26 +28,6 @@ interface OnSuccessResponder<T$1 extends {
27
28
  subject?: string;
28
29
  }): Promise<Response>;
29
30
  }
30
- /**
31
- * Authorization state for OAuth 2.0 flows.
32
- */
33
- interface AuthorizationState {
34
- /** OAuth redirect URI */
35
- redirect_uri: string;
36
- /** OAuth response type */
37
- response_type: string;
38
- /** OAuth state parameter for CSRF protection */
39
- state: string;
40
- /** OAuth client identifier */
41
- client_id: string;
42
- /** OAuth audience parameter */
43
- audience: string;
44
- /** PKCE challenge data for code verification */
45
- pkce?: {
46
- challenge: string;
47
- method: "S256";
48
- };
49
- }
50
31
  /**
51
32
  * Main issuer input configuration interface.
52
33
  */
@@ -129,4 +110,4 @@ declare const issuer: <Providers extends Record<string, Provider<unknown>>, Subj
129
110
  };
130
111
  }>;
131
112
  //#endregion
132
- export { AuthorizationState, OnSuccessResponder, issuer };
113
+ export { OnSuccessResponder, issuer };
package/dist/core.mjs CHANGED
@@ -139,7 +139,8 @@ const issuer = (input) => {
139
139
  clientID: value.clientID,
140
140
  subject: value.subject,
141
141
  ttl: value.ttl,
142
- nextToken: generateSecureToken()
142
+ nextToken: generateSecureToken(),
143
+ timeUsed: value.timeUsed
143
144
  };
144
145
  const refreshKey = [
145
146
  "oauth:refresh",
@@ -231,6 +232,7 @@ const issuer = (input) => {
231
232
  subject,
232
233
  redirectURI: authorization.redirect_uri,
233
234
  clientID: authorization.client_id,
235
+ scopes: authorization.scopes,
234
236
  pkce: authorization.pkce,
235
237
  ttl: {
236
238
  access: subjectOpts?.ttl?.access ?? ttlAccess,
@@ -492,13 +494,51 @@ const issuer = (input) => {
492
494
  credentials: false
493
495
  })],
494
496
  handler: async (c) => {
495
- const token = (await c.formData()).get("token")?.toString();
497
+ const form = await c.formData();
498
+ const token = form.get("token")?.toString();
499
+ const tokenTypeHint = form.get("token_type_hint")?.toString();
496
500
  if (!token) {
497
501
  const error$1 = new OauthError("invalid_request", "Missing token parameter");
498
502
  return c.json(error$1.toJSON(), { status: 400 });
499
503
  }
500
504
  try {
501
- const expiresAt = Date.now() + ttlRefresh * 1e3;
505
+ if (tokenTypeHint === "refresh_token") {
506
+ const splits$1 = token.split(":");
507
+ const tokenPart$1 = splits$1.pop();
508
+ if (tokenPart$1 && splits$1.length > 0) {
509
+ const key = [
510
+ "oauth:refresh",
511
+ splits$1.join(":"),
512
+ tokenPart$1
513
+ ];
514
+ if (await Storage.get(storage, key)) {
515
+ await Storage.remove(storage, key);
516
+ const expiresAt$1 = Date.now() + ttlRefreshRetention * 1e3;
517
+ await Revocation.revoke(storage, token, expiresAt$1);
518
+ return c.json({});
519
+ }
520
+ }
521
+ } else if (tokenTypeHint === "access_token") {
522
+ const expiresAt$1 = Date.now() + ttlAccess * 1e3;
523
+ await Revocation.revoke(storage, token, expiresAt$1);
524
+ return c.json({});
525
+ }
526
+ const splits = token.split(":");
527
+ const tokenPart = splits.pop();
528
+ if (tokenPart && splits.length > 0) {
529
+ const key = [
530
+ "oauth:refresh",
531
+ splits.join(":"),
532
+ tokenPart
533
+ ];
534
+ if (await Storage.get(storage, key)) {
535
+ await Storage.remove(storage, key);
536
+ const expiresAt$1 = Date.now() + ttlRefreshRetention * 1e3;
537
+ await Revocation.revoke(storage, token, expiresAt$1);
538
+ return c.json({});
539
+ }
540
+ }
541
+ const expiresAt = Date.now() + ttlAccess * 1e3;
502
542
  await Revocation.revoke(storage, token, expiresAt);
503
543
  return c.json({});
504
544
  } catch (_err) {
@@ -526,6 +566,7 @@ const issuer = (input) => {
526
566
  client_id,
527
567
  audience,
528
568
  scope,
569
+ scopes: scope ? scope.split(" ").filter(Boolean) : void 0,
529
570
  ...code_challenge && code_challenge_method && { pkce: {
530
571
  challenge: code_challenge,
531
572
  method: code_challenge_method
@@ -2,6 +2,7 @@ import { getRelativeUrl } from "../util.mjs";
2
2
  import { OauthError } from "../error.mjs";
3
3
  import { generatePKCE } from "../pkce.mjs";
4
4
  import { generateSecureToken, timingSafeCompare } from "../random.mjs";
5
+ import { createRemoteJWKSet, jwtVerify } from "jose";
5
6
 
6
7
  //#region src/provider/oauth2.ts
7
8
  /**
@@ -70,6 +71,12 @@ const Oauth2Provider = (config) => {
70
71
  if (!response.ok) throw new Error(`Token request failed with status ${response.status}`);
71
72
  const tokenData = await response.json();
72
73
  if (tokenData.error) throw new OauthError(tokenData.error, tokenData.error_description || "");
74
+ if (tokenData.id_token && config.endpoint.jwks) try {
75
+ const jwks = createRemoteJWKSet(new URL(config.endpoint.jwks));
76
+ await jwtVerify(tokenData.id_token, jwks, { issuer: config.endpoint.authorization.split("/").slice(0, 3).join("/") });
77
+ } catch (error) {
78
+ throw new OauthError("invalid_request", `ID token validation failed: ${error instanceof Error ? error.message : "Unknown error"}`);
79
+ }
73
80
  return await ctx.success(c, {
74
81
  clientID: config.clientID,
75
82
  tokenset: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@draftlab/auth",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "Core implementation for @draftlab/auth",
6
6
  "author": "Matheus Pergoli",
@@ -39,7 +39,7 @@
39
39
  "devDependencies": {
40
40
  "@types/node": "^24.10.1",
41
41
  "@types/qrcode": "^1.5.6",
42
- "tsdown": "^0.16.6",
42
+ "tsdown": "^0.16.7",
43
43
  "typescript": "^5.9.3",
44
44
  "@draftlab/tsconfig": "0.1.0"
45
45
  },
@@ -63,7 +63,7 @@
63
63
  "preact": "^10.27.2",
64
64
  "preact-render-to-string": "^6.6.3",
65
65
  "qrcode": "^1.5.4",
66
- "@draftlab/auth-router": "0.1.0"
66
+ "@draftlab/auth-router": "0.2.0"
67
67
  },
68
68
  "engines": {
69
69
  "node": ">=18"