@codefox-inc/oauth-provider 0.2.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 (113) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +572 -0
  3. package/dist/client/_generated/_ignore.d.ts +1 -0
  4. package/dist/client/_generated/_ignore.d.ts.map +1 -0
  5. package/dist/client/_generated/_ignore.js +3 -0
  6. package/dist/client/_generated/_ignore.js.map +1 -0
  7. package/dist/client/auth-config.d.ts +85 -0
  8. package/dist/client/auth-config.d.ts.map +1 -0
  9. package/dist/client/auth-config.js +81 -0
  10. package/dist/client/auth-config.js.map +1 -0
  11. package/dist/client/auth-helper.d.ts +81 -0
  12. package/dist/client/auth-helper.d.ts.map +1 -0
  13. package/dist/client/auth-helper.js +97 -0
  14. package/dist/client/auth-helper.js.map +1 -0
  15. package/dist/client/index.d.ts +189 -0
  16. package/dist/client/index.d.ts.map +1 -0
  17. package/dist/client/index.js +230 -0
  18. package/dist/client/index.js.map +1 -0
  19. package/dist/client/routes.d.ts +94 -0
  20. package/dist/client/routes.d.ts.map +1 -0
  21. package/dist/client/routes.js +113 -0
  22. package/dist/client/routes.js.map +1 -0
  23. package/dist/component/_generated/api.d.ts +44 -0
  24. package/dist/component/_generated/api.d.ts.map +1 -0
  25. package/dist/component/_generated/api.js +31 -0
  26. package/dist/component/_generated/api.js.map +1 -0
  27. package/dist/component/_generated/component.d.ts +123 -0
  28. package/dist/component/_generated/component.d.ts.map +1 -0
  29. package/dist/component/_generated/component.js +11 -0
  30. package/dist/component/_generated/component.js.map +1 -0
  31. package/dist/component/_generated/dataModel.d.ts +46 -0
  32. package/dist/component/_generated/dataModel.d.ts.map +1 -0
  33. package/dist/component/_generated/dataModel.js +11 -0
  34. package/dist/component/_generated/dataModel.js.map +1 -0
  35. package/dist/component/_generated/server.d.ts +121 -0
  36. package/dist/component/_generated/server.d.ts.map +1 -0
  37. package/dist/component/_generated/server.js +78 -0
  38. package/dist/component/_generated/server.js.map +1 -0
  39. package/dist/component/clientManagement.d.ts +39 -0
  40. package/dist/component/clientManagement.d.ts.map +1 -0
  41. package/dist/component/clientManagement.js +169 -0
  42. package/dist/component/clientManagement.js.map +1 -0
  43. package/dist/component/constants.d.ts +31 -0
  44. package/dist/component/constants.d.ts.map +1 -0
  45. package/dist/component/constants.js +36 -0
  46. package/dist/component/constants.js.map +1 -0
  47. package/dist/component/convex.config.d.ts +3 -0
  48. package/dist/component/convex.config.d.ts.map +1 -0
  49. package/dist/component/convex.config.js +3 -0
  50. package/dist/component/convex.config.js.map +1 -0
  51. package/dist/component/handlers.d.ts +143 -0
  52. package/dist/component/handlers.d.ts.map +1 -0
  53. package/dist/component/handlers.js +624 -0
  54. package/dist/component/handlers.js.map +1 -0
  55. package/dist/component/mutations.d.ts +111 -0
  56. package/dist/component/mutations.d.ts.map +1 -0
  57. package/dist/component/mutations.js +459 -0
  58. package/dist/component/mutations.js.map +1 -0
  59. package/dist/component/queries.d.ts +127 -0
  60. package/dist/component/queries.d.ts.map +1 -0
  61. package/dist/component/queries.js +145 -0
  62. package/dist/component/queries.js.map +1 -0
  63. package/dist/component/schema.d.ts +116 -0
  64. package/dist/component/schema.d.ts.map +1 -0
  65. package/dist/component/schema.js +77 -0
  66. package/dist/component/schema.js.map +1 -0
  67. package/dist/component/token_security.d.ts +53 -0
  68. package/dist/component/token_security.d.ts.map +1 -0
  69. package/dist/component/token_security.js +91 -0
  70. package/dist/component/token_security.js.map +1 -0
  71. package/dist/lib/convex-types.d.ts +21 -0
  72. package/dist/lib/convex-types.d.ts.map +1 -0
  73. package/dist/lib/convex-types.js +2 -0
  74. package/dist/lib/convex-types.js.map +1 -0
  75. package/dist/lib/oauth.d.ts +123 -0
  76. package/dist/lib/oauth.d.ts.map +1 -0
  77. package/dist/lib/oauth.js +295 -0
  78. package/dist/lib/oauth.js.map +1 -0
  79. package/dist/react/index.d.ts +2 -0
  80. package/dist/react/index.d.ts.map +1 -0
  81. package/dist/react/index.js +6 -0
  82. package/dist/react/index.js.map +1 -0
  83. package/package.json +121 -0
  84. package/src/client/__tests__/auth-config.test.ts +244 -0
  85. package/src/client/__tests__/auth-helper.test.ts +273 -0
  86. package/src/client/__tests__/oauth-provider.test.ts +418 -0
  87. package/src/client/__tests__/routes.test.ts +428 -0
  88. package/src/client/_generated/_ignore.ts +1 -0
  89. package/src/client/auth-config.ts +157 -0
  90. package/src/client/auth-helper.ts +201 -0
  91. package/src/client/index.ts +326 -0
  92. package/src/client/routes.ts +251 -0
  93. package/src/component/__tests__/oauth.test.ts +3310 -0
  94. package/src/component/__tests__/rfc-compliance.test.ts +788 -0
  95. package/src/component/__tests__/token-security.test.ts +133 -0
  96. package/src/component/_generated/api.ts +60 -0
  97. package/src/component/_generated/component.ts +201 -0
  98. package/src/component/_generated/dataModel.ts +60 -0
  99. package/src/component/_generated/server.ts +156 -0
  100. package/src/component/clientManagement.ts +189 -0
  101. package/src/component/constants.ts +40 -0
  102. package/src/component/convex.config.ts +3 -0
  103. package/src/component/handlers.ts +964 -0
  104. package/src/component/mutations.ts +531 -0
  105. package/src/component/queries.ts +165 -0
  106. package/src/component/schema.ts +92 -0
  107. package/src/component/token_security.ts +102 -0
  108. package/src/lib/__tests__/oauth-helpers.test.ts +143 -0
  109. package/src/lib/__tests__/oauth-jwt.test.ts +405 -0
  110. package/src/lib/convex-types.ts +37 -0
  111. package/src/lib/oauth.ts +412 -0
  112. package/src/react/index.ts +7 -0
  113. package/src/test.ts +21 -0
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Check if a URI is a loopback address (localhost, 127.0.0.1, ::1)
3
+ * RFC 8252 Section 7.3: Loopback redirect URIs with variable ports
4
+ */
5
+ export declare function isLoopbackRedirectUri(uri: string): boolean;
6
+ /**
7
+ * Match redirect URI with registered URIs
8
+ * RFC 6749 Section 3.1.2.3: Exact string matching required
9
+ * RFC 8252 Section 7.3: Exception for loopback URIs (variable ports allowed)
10
+ */
11
+ export declare function matchRedirectUri(requested: string, registered: string[]): boolean;
12
+ /**
13
+ * Issue Authorization Code
14
+ * RFC 7636: PKCE validation
15
+ * RFC 6749 Section 3.1.2.3: Redirect URI validation
16
+ */
17
+ export declare const issueAuthorizationCode: import("convex/server").RegisteredMutation<"public", {
18
+ nonce?: string | undefined;
19
+ clientId: string;
20
+ userId: string;
21
+ scopes: string[];
22
+ redirectUri: string;
23
+ codeChallenge: string;
24
+ codeChallengeMethod: string;
25
+ }, Promise<string>>;
26
+ /**
27
+ * Validate and Consume Authorization Code
28
+ * Returns code data if valid, throws otherwise.
29
+ * Marks the code as used (not deleted) to detect replay attacks.
30
+ * RFC Line 1136: SHOULD revoke all tokens if code is reused.
31
+ * RFC Section 10.2: OAuth 2.1 - redirect_uri is OPTIONAL
32
+ */
33
+ export declare const consumeAuthCode: import("convex/server").RegisteredMutation<"public", {
34
+ redirectUri?: string | undefined;
35
+ clientId: string;
36
+ code: string;
37
+ codeVerifier: string;
38
+ }, Promise<any>>;
39
+ /**
40
+ * Save Tokens
41
+ *
42
+ * Note: Tokens are stored as SHA-256 hashes for security.
43
+ * The original token value should be returned to the client, not stored.
44
+ */
45
+ export declare const saveTokens: import("convex/server").RegisteredMutation<"public", {
46
+ refreshToken?: string | undefined;
47
+ refreshTokenExpiresAt?: number | undefined;
48
+ authorizationCode?: string | undefined;
49
+ clientId: string;
50
+ userId: string;
51
+ scopes: string[];
52
+ expiresAt: number;
53
+ accessToken: string;
54
+ }, Promise<void>>;
55
+ /**
56
+ * Rotate Refresh Token (Delete old, Insert new)
57
+ * RFC 4.3.3: New refresh token MUST have identical scope as the old one
58
+ *
59
+ * Note: Tokens are stored as SHA-256 hashes for security.
60
+ */
61
+ export declare const rotateRefreshToken: import("convex/server").RegisteredMutation<"public", {
62
+ refreshToken?: string | undefined;
63
+ refreshTokenExpiresAt?: number | undefined;
64
+ clientId: string;
65
+ userId: string;
66
+ scopes: string[];
67
+ expiresAt: number;
68
+ accessToken: string;
69
+ oldRefreshToken: string;
70
+ }, Promise<void>>;
71
+ /**
72
+ * Delete Client
73
+ */
74
+ export declare const deleteClient: import("convex/server").RegisteredMutation<"public", {
75
+ clientId: string;
76
+ }, Promise<void>>;
77
+ /**
78
+ * Clean up expired codes/tokens (utility)
79
+ * RFC Line 1136: Also cleanup used codes after retention period
80
+ */
81
+ export declare const cleanupExpired: import("convex/server").RegisteredMutation<"internal", {}, Promise<{
82
+ deletedCodes: number;
83
+ deletedTokens: number;
84
+ }>>;
85
+ /**
86
+ * Create or update authorization (upsert)
87
+ * Called when user grants consent
88
+ */
89
+ export declare const upsertAuthorization: import("convex/server").RegisteredMutation<"public", {
90
+ clientId: string;
91
+ userId: string;
92
+ scopes: string[];
93
+ }, Promise<import("convex/values").GenericId<"oauthAuthorizations">>>;
94
+ /**
95
+ * Update lastUsedAt when tokens are issued
96
+ */
97
+ export declare const updateAuthorizationLastUsed: import("convex/server").RegisteredMutation<"public", {
98
+ clientId: string;
99
+ userId: string;
100
+ }, Promise<void>>;
101
+ /**
102
+ * Revoke authorization and delete all associated tokens
103
+ */
104
+ export declare const revokeAuthorization: import("convex/server").RegisteredMutation<"public", {
105
+ clientId: string;
106
+ userId: string;
107
+ }, Promise<{
108
+ authorizationDeleted: boolean;
109
+ tokensDeleted: number;
110
+ }>>;
111
+ //# sourceMappingURL=mutations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutations.d.ts","sourceRoot":"","sources":["../../src/component/mutations.ts"],"names":[],"mappings":"AAUA;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW1D;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,OAAO,CA4BjF;AAMD;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;mBA4DjC,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;gBA0G1B,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,UAAU;;;;;;;;;iBAsBrB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;iBAmF7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;iBAgBvB,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,cAAc;;;GA8BzB,CAAC;AAMH;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;qEAmC9B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,2BAA2B;;;iBAiBtC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;GAkC9B,CAAC"}
@@ -0,0 +1,459 @@
1
+ import { v } from "convex/values";
2
+ import { mutation, internalMutation } from "./_generated/server";
3
+ import { generateCode } from "../lib/oauth.js";
4
+ import { OAUTH_CONSTANTS } from "./constants";
5
+ import { hashToken, isHashedToken } from "./token_security";
6
+ // --------------------------------------------------------------------------
7
+ // Helper Functions
8
+ // --------------------------------------------------------------------------
9
+ /**
10
+ * Check if a URI is a loopback address (localhost, 127.0.0.1, ::1)
11
+ * RFC 8252 Section 7.3: Loopback redirect URIs with variable ports
12
+ */
13
+ export function isLoopbackRedirectUri(uri) {
14
+ try {
15
+ const parsed = new URL(uri);
16
+ return (parsed.hostname === "127.0.0.1" ||
17
+ parsed.hostname === "::1" ||
18
+ parsed.hostname === "localhost");
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ /**
25
+ * Match redirect URI with registered URIs
26
+ * RFC 6749 Section 3.1.2.3: Exact string matching required
27
+ * RFC 8252 Section 7.3: Exception for loopback URIs (variable ports allowed)
28
+ */
29
+ export function matchRedirectUri(requested, registered) {
30
+ // 厳密一致チェック
31
+ if (registered.includes(requested)) {
32
+ return true;
33
+ }
34
+ // localhost/127.0.0.1の可変ポート例外(RFC 8252 Section 7.3)
35
+ if (isLoopbackRedirectUri(requested)) {
36
+ try {
37
+ const reqUrl = new URL(requested);
38
+ for (const regUri of registered) {
39
+ if (isLoopbackRedirectUri(regUri)) {
40
+ const regUrl = new URL(regUri);
41
+ // ホストとパスが一致すればポート違いを許容
42
+ if (reqUrl.hostname === regUrl.hostname &&
43
+ reqUrl.pathname === regUrl.pathname) {
44
+ return true;
45
+ }
46
+ }
47
+ }
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ return false;
54
+ }
55
+ // --------------------------------------------------------------------------
56
+ // Authorization Code Flow
57
+ // --------------------------------------------------------------------------
58
+ /**
59
+ * Issue Authorization Code
60
+ * RFC 7636: PKCE validation
61
+ * RFC 6749 Section 3.1.2.3: Redirect URI validation
62
+ */
63
+ export const issueAuthorizationCode = mutation({
64
+ args: {
65
+ clientId: v.string(),
66
+ userId: v.string(), // Convex users table Id (string, passed from app)
67
+ scopes: v.array(v.string()),
68
+ redirectUri: v.string(),
69
+ codeChallenge: v.string(),
70
+ codeChallengeMethod: v.string(),
71
+ nonce: v.optional(v.string()),
72
+ },
73
+ handler: async (ctx, args) => {
74
+ // 1. PKCE検証(RFC 7636)
75
+ if (!args.codeChallenge || args.codeChallenge.trim() === "") {
76
+ throw new Error("code_challenge required");
77
+ }
78
+ if (args.codeChallengeMethod !== "S256") {
79
+ throw new Error("plain code_challenge_method is not supported, use S256");
80
+ }
81
+ // 2. クライアント取得
82
+ const client = await ctx.db
83
+ .query("oauthClients")
84
+ .withIndex("by_client_id", (q) => q.eq("clientId", args.clientId))
85
+ .unique();
86
+ if (!client) {
87
+ throw new Error("invalid_client");
88
+ }
89
+ // 3. リダイレクトURI検証(RFC 6749 + RFC 8252)
90
+ if (!matchRedirectUri(args.redirectUri, client.redirectUris)) {
91
+ throw new Error("redirect_uri_mismatch");
92
+ }
93
+ // 4. スコープ検証
94
+ const invalidScopes = args.scopes.filter((scope) => !client.allowedScopes.includes(scope));
95
+ if (invalidScopes.length > 0) {
96
+ throw new Error(`invalid_scope: ${invalidScopes.join(", ")}`);
97
+ }
98
+ // 5. Generate Code
99
+ const code = generateCode(OAUTH_CONSTANTS.AUTH_CODE_LENGTH);
100
+ // 6. Save Code (hashed for security)
101
+ await ctx.db.insert("oauthCodes", {
102
+ code: await hashToken(code),
103
+ clientId: args.clientId,
104
+ userId: args.userId,
105
+ scopes: args.scopes,
106
+ redirectUri: args.redirectUri,
107
+ codeChallenge: args.codeChallenge,
108
+ codeChallengeMethod: args.codeChallengeMethod,
109
+ nonce: args.nonce,
110
+ expiresAt: Date.now() + OAUTH_CONSTANTS.CODE_EXPIRY_MS,
111
+ });
112
+ return code;
113
+ },
114
+ });
115
+ /**
116
+ * Validate and Consume Authorization Code
117
+ * Returns code data if valid, throws otherwise.
118
+ * Marks the code as used (not deleted) to detect replay attacks.
119
+ * RFC Line 1136: SHOULD revoke all tokens if code is reused.
120
+ * RFC Section 10.2: OAuth 2.1 - redirect_uri is OPTIONAL
121
+ */
122
+ export const consumeAuthCode = mutation({
123
+ args: {
124
+ code: v.string(),
125
+ clientId: v.string(),
126
+ redirectUri: v.optional(v.string()), // OAuth 2.1: optional
127
+ codeVerifier: v.string(),
128
+ },
129
+ handler: async (ctx, args) => {
130
+ // 1. Find Code (by hash)
131
+ const codeHash = await hashToken(args.code);
132
+ let authCode = await ctx.db
133
+ .query("oauthCodes")
134
+ .withIndex("by_code", (q) => q.eq("code", codeHash))
135
+ .unique();
136
+ // Backward compatibility: try plaintext lookup if hash lookup fails
137
+ if (!authCode && !isHashedToken(args.code)) {
138
+ authCode = await ctx.db
139
+ .query("oauthCodes")
140
+ .withIndex("by_code", (q) => q.eq("code", args.code))
141
+ .unique();
142
+ }
143
+ if (!authCode) {
144
+ throw new Error("invalid_grant");
145
+ }
146
+ // RFC Line 1136: Detect authorization code reuse (replay attack)
147
+ if (authCode.usedAt !== undefined) {
148
+ // Code was already used - this is a replay attack
149
+ // Revoke all tokens issued with this code
150
+ const tokensToRevoke = await ctx.db
151
+ .query("oauthTokens")
152
+ .withIndex("by_authorization_code", (q) => q.eq("authorizationCode", codeHash))
153
+ .collect();
154
+ for (const token of tokensToRevoke) {
155
+ await ctx.db.delete(token._id);
156
+ }
157
+ // Delete the code
158
+ await ctx.db.delete(authCode._id);
159
+ // Return error status (cannot throw because it would rollback token deletion)
160
+ return {
161
+ error: "authorization_code_reuse_detected",
162
+ revokedTokens: tokensToRevoke.length,
163
+ };
164
+ }
165
+ // 2. Validation
166
+ if (authCode.clientId !== args.clientId) {
167
+ throw new Error("invalid_client");
168
+ }
169
+ if (authCode.expiresAt < Date.now()) {
170
+ await ctx.db.delete(authCode._id);
171
+ throw new Error("invalid_grant");
172
+ }
173
+ // redirect_uri validation: 発行時に設定されている場合は必須
174
+ // RFC 6749 Section 4.1.3: redirect_uri REQUIRED if included in authorization request
175
+ if (authCode.redirectUri) {
176
+ if (!args.redirectUri) {
177
+ throw new Error("redirect_uri_required");
178
+ }
179
+ if (authCode.redirectUri !== args.redirectUri) {
180
+ throw new Error("redirect_uri_mismatch");
181
+ }
182
+ }
183
+ // PKCE検証(エラーメッセージ改善)
184
+ if (authCode.codeChallengeMethod === "S256") {
185
+ const encoder = new TextEncoder();
186
+ const data = encoder.encode(args.codeVerifier);
187
+ const hashBuffer = await crypto.subtle.digest("SHA-256", data);
188
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
189
+ const hashBase64 = btoa(String.fromCharCode(...hashArray))
190
+ .replace(/\+/g, "-")
191
+ .replace(/\//g, "_")
192
+ .replace(/=+$/, "");
193
+ if (hashBase64 !== authCode.codeChallenge) {
194
+ throw new Error("invalid_code_verifier");
195
+ }
196
+ }
197
+ else if (authCode.codeChallengeMethod === "plain") {
198
+ if (args.codeVerifier !== authCode.codeChallenge) {
199
+ throw new Error("invalid_code_verifier");
200
+ }
201
+ }
202
+ else {
203
+ throw new Error("unsupported_code_challenge_method");
204
+ }
205
+ // 3. Mark Code as Used (RFC Line 1136: detect replay)
206
+ await ctx.db.patch(authCode._id, { usedAt: Date.now() });
207
+ return {
208
+ userId: authCode.userId,
209
+ scopes: authCode.scopes,
210
+ codeChallenge: authCode.codeChallenge,
211
+ codeChallengeMethod: authCode.codeChallengeMethod,
212
+ redirectUri: authCode.redirectUri,
213
+ nonce: authCode.nonce,
214
+ codeHash, // Return code hash to link tokens
215
+ };
216
+ },
217
+ });
218
+ /**
219
+ * Save Tokens
220
+ *
221
+ * Note: Tokens are stored as SHA-256 hashes for security.
222
+ * The original token value should be returned to the client, not stored.
223
+ */
224
+ export const saveTokens = mutation({
225
+ args: {
226
+ accessToken: v.string(),
227
+ refreshToken: v.optional(v.string()),
228
+ clientId: v.string(),
229
+ userId: v.string(),
230
+ scopes: v.array(v.string()),
231
+ expiresAt: v.number(),
232
+ refreshTokenExpiresAt: v.optional(v.number()),
233
+ authorizationCode: v.optional(v.string()), // Hashed code for replay detection (RFC Line 1136)
234
+ },
235
+ handler: async (ctx, args) => {
236
+ // Hash tokens before storing for security
237
+ // The original tokens are returned to the client, hashes are stored
238
+ await ctx.db.insert("oauthTokens", {
239
+ ...args,
240
+ accessToken: await hashToken(args.accessToken),
241
+ refreshToken: args.refreshToken
242
+ ? await hashToken(args.refreshToken)
243
+ : undefined,
244
+ });
245
+ },
246
+ });
247
+ /**
248
+ * Rotate Refresh Token (Delete old, Insert new)
249
+ * RFC 4.3.3: New refresh token MUST have identical scope as the old one
250
+ *
251
+ * Note: Tokens are stored as SHA-256 hashes for security.
252
+ */
253
+ export const rotateRefreshToken = mutation({
254
+ args: {
255
+ oldRefreshToken: v.string(),
256
+ // New Token Data
257
+ accessToken: v.string(),
258
+ refreshToken: v.optional(v.string()),
259
+ clientId: v.string(),
260
+ userId: v.string(),
261
+ scopes: v.array(v.string()),
262
+ expiresAt: v.number(),
263
+ refreshTokenExpiresAt: v.optional(v.number()),
264
+ },
265
+ handler: async (ctx, args) => {
266
+ // Hash the old refresh token for lookup
267
+ const oldRefreshTokenHash = await hashToken(args.oldRefreshToken);
268
+ // 1. Verify Old Token Exists (lookup by hash)
269
+ let oldToken = await ctx.db
270
+ .query("oauthTokens")
271
+ .withIndex("by_refresh_token", (q) => q.eq("refreshToken", oldRefreshTokenHash))
272
+ .unique();
273
+ // Backward compatibility: try plaintext lookup if hash lookup fails
274
+ if (!oldToken && !isHashedToken(args.oldRefreshToken)) {
275
+ oldToken = await ctx.db
276
+ .query("oauthTokens")
277
+ .withIndex("by_refresh_token", (q) => q.eq("refreshToken", args.oldRefreshToken))
278
+ .unique();
279
+ }
280
+ if (!oldToken) {
281
+ throw new Error("invalid_grant");
282
+ }
283
+ // 2. Validate Client/User consistency
284
+ if (oldToken.clientId !== args.clientId || oldToken.userId !== args.userId) {
285
+ throw new Error("invalid_grant");
286
+ }
287
+ // 3. RFC 4.3.3: 新RTのスコープは元RTと完全一致が必須
288
+ // スコープの完全一致を検証(エスカレーションも縮小も不可)
289
+ const scopesMatch = args.scopes.length === oldToken.scopes.length &&
290
+ args.scopes.every((scope) => oldToken.scopes.includes(scope)) &&
291
+ oldToken.scopes.every((scope) => args.scopes.includes(scope));
292
+ if (!scopesMatch) {
293
+ throw new Error("scope_change_not_allowed: Refresh token scope must remain identical");
294
+ }
295
+ // 4. クライアントの許可スコープ検証
296
+ const client = await ctx.db
297
+ .query("oauthClients")
298
+ .withIndex("by_client_id", (q) => q.eq("clientId", args.clientId))
299
+ .unique();
300
+ if (!client) {
301
+ throw new Error("invalid_client");
302
+ }
303
+ const invalidScopes = args.scopes.filter((scope) => !client.allowedScopes.includes(scope));
304
+ if (invalidScopes.length > 0) {
305
+ throw new Error(`invalid_scope: ${invalidScopes.join(", ")}`);
306
+ }
307
+ // 5. Delete Old Token
308
+ await ctx.db.delete(oldToken._id);
309
+ // 6. Insert New Token (with hashed values)
310
+ await ctx.db.insert("oauthTokens", {
311
+ accessToken: await hashToken(args.accessToken),
312
+ refreshToken: args.refreshToken ? await hashToken(args.refreshToken) : undefined,
313
+ clientId: args.clientId,
314
+ userId: args.userId,
315
+ scopes: args.scopes,
316
+ expiresAt: args.expiresAt,
317
+ refreshTokenExpiresAt: args.refreshTokenExpiresAt,
318
+ });
319
+ },
320
+ });
321
+ /**
322
+ * Delete Client
323
+ */
324
+ export const deleteClient = mutation({
325
+ args: {
326
+ clientId: v.string(),
327
+ },
328
+ handler: async (ctx, args) => {
329
+ const client = await ctx.db
330
+ .query("oauthClients")
331
+ .withIndex("by_client_id", (q) => q.eq("clientId", args.clientId))
332
+ .unique();
333
+ if (!client) {
334
+ throw new Error("Client not found");
335
+ }
336
+ await ctx.db.delete(client._id);
337
+ },
338
+ });
339
+ /**
340
+ * Clean up expired codes/tokens (utility)
341
+ * RFC Line 1136: Also cleanup used codes after retention period
342
+ */
343
+ export const cleanupExpired = internalMutation({
344
+ args: {},
345
+ handler: async (ctx) => {
346
+ const now = Date.now();
347
+ // Cleanup expired codes (both unused and used codes past retention period)
348
+ const expiredCodes = await ctx.db
349
+ .query("oauthCodes")
350
+ .filter(q => q.lt(q.field("expiresAt"), now))
351
+ .take(100);
352
+ for (const code of expiredCodes) {
353
+ await ctx.db.delete(code._id);
354
+ }
355
+ // Cleanup expired tokens
356
+ const expiredTokens = await ctx.db
357
+ .query("oauthTokens")
358
+ .filter(q => q.lt(q.field("expiresAt"), now))
359
+ .take(100);
360
+ for (const token of expiredTokens) {
361
+ await ctx.db.delete(token._id);
362
+ }
363
+ return {
364
+ deletedCodes: expiredCodes.length,
365
+ deletedTokens: expiredTokens.length,
366
+ };
367
+ }
368
+ });
369
+ // --------------------------------------------------------------------------
370
+ // Authorization Management
371
+ // --------------------------------------------------------------------------
372
+ /**
373
+ * Create or update authorization (upsert)
374
+ * Called when user grants consent
375
+ */
376
+ export const upsertAuthorization = mutation({
377
+ args: {
378
+ userId: v.string(),
379
+ clientId: v.string(),
380
+ scopes: v.array(v.string()),
381
+ },
382
+ handler: async (ctx, args) => {
383
+ const existing = await ctx.db
384
+ .query("oauthAuthorizations")
385
+ .withIndex("by_user_client", (q) => q.eq("userId", args.userId).eq("clientId", args.clientId))
386
+ .unique();
387
+ const now = Date.now();
388
+ if (existing) {
389
+ // Update: merge scopes, update lastUsedAt
390
+ const mergedScopes = [...new Set([...existing.scopes, ...args.scopes])];
391
+ await ctx.db.patch(existing._id, {
392
+ scopes: mergedScopes,
393
+ lastUsedAt: now,
394
+ });
395
+ return existing._id;
396
+ }
397
+ else {
398
+ // Create new authorization
399
+ return await ctx.db.insert("oauthAuthorizations", {
400
+ userId: args.userId,
401
+ clientId: args.clientId,
402
+ scopes: args.scopes,
403
+ authorizedAt: now,
404
+ lastUsedAt: now,
405
+ });
406
+ }
407
+ },
408
+ });
409
+ /**
410
+ * Update lastUsedAt when tokens are issued
411
+ */
412
+ export const updateAuthorizationLastUsed = mutation({
413
+ args: {
414
+ userId: v.string(),
415
+ clientId: v.string(),
416
+ },
417
+ handler: async (ctx, args) => {
418
+ const auth = await ctx.db
419
+ .query("oauthAuthorizations")
420
+ .withIndex("by_user_client", (q) => q.eq("userId", args.userId).eq("clientId", args.clientId))
421
+ .unique();
422
+ if (auth) {
423
+ await ctx.db.patch(auth._id, { lastUsedAt: Date.now() });
424
+ }
425
+ },
426
+ });
427
+ /**
428
+ * Revoke authorization and delete all associated tokens
429
+ */
430
+ export const revokeAuthorization = mutation({
431
+ args: {
432
+ userId: v.string(),
433
+ clientId: v.string(),
434
+ },
435
+ handler: async (ctx, args) => {
436
+ // 1. Delete authorization record
437
+ const auth = await ctx.db
438
+ .query("oauthAuthorizations")
439
+ .withIndex("by_user_client", (q) => q.eq("userId", args.userId).eq("clientId", args.clientId))
440
+ .unique();
441
+ if (auth) {
442
+ await ctx.db.delete(auth._id);
443
+ }
444
+ // 2. Delete all tokens for this user-client pair
445
+ const tokens = await ctx.db
446
+ .query("oauthTokens")
447
+ .withIndex("by_user", (q) => q.eq("userId", args.userId))
448
+ .collect();
449
+ const toDelete = tokens.filter(t => t.clientId === args.clientId);
450
+ for (const token of toDelete) {
451
+ await ctx.db.delete(token._id);
452
+ }
453
+ return {
454
+ authorizationDeleted: !!auth,
455
+ tokensDeleted: toDelete.length,
456
+ };
457
+ },
458
+ });
459
+ //# sourceMappingURL=mutations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutations.js","sourceRoot":"","sources":["../../src/component/mutations.ts"],"names":[],"mappings":"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"}