@robelest/convex-auth 0.0.4-preview.27 → 0.0.4-preview.28
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/README.md +3 -5
- package/dist/bin.js +6488 -1571
- package/dist/browser/index.js +10 -7
- package/dist/browser/locks.js +3 -5
- package/dist/browser/navigation.js +7 -10
- package/dist/browser/runtime.js +35 -33
- package/dist/client/core/types.js +17 -0
- package/dist/client/factors/device.js +26 -19
- package/dist/client/index.js +151 -163
- package/dist/client/runtime/proxy.js +6 -6
- package/dist/client/services/adapters.js +3 -7
- package/dist/client/services/http.js +2 -5
- package/dist/client/services/resolve.js +5 -11
- package/dist/client/services/runtime.js +2 -5
- package/dist/component/_generated/component.d.ts +46 -0
- package/dist/component/index.d.ts +3 -3
- package/dist/component/model.d.ts +25 -25
- package/dist/component/public/identity/sessions.js +38 -1
- package/dist/component/public/identity/tokens.js +81 -3
- package/dist/component/public/identity/verifiers.js +9 -3
- package/dist/component/public.js +3 -3
- package/dist/component/schema.d.ts +320 -320
- package/dist/core/index.d.ts +380 -0
- package/dist/core/index.js +83 -0
- package/dist/otel.d.ts +13 -17
- package/dist/otel.js +39 -49
- package/dist/providers/email.d.ts +2 -2
- package/dist/providers/password.js +8 -16
- package/dist/providers/phone.js +2 -9
- package/dist/server/auth-context.d.ts +204 -0
- package/dist/server/auth-context.js +76 -0
- package/dist/server/auth.d.ts +25 -187
- package/dist/server/auth.js +5 -96
- package/dist/server/componentContext.d.ts +12 -0
- package/dist/server/componentContext.js +1 -0
- package/dist/server/config.js +1 -12
- package/dist/server/constants.js +6 -0
- package/dist/server/contract.d.ts +1 -1
- package/dist/server/core.js +5 -14
- package/dist/server/crypto.js +26 -18
- package/dist/server/db.js +6 -1
- package/dist/server/device.js +88 -78
- package/dist/server/http.d.ts +4 -3
- package/dist/server/http.js +74 -86
- package/dist/server/index.d.ts +2 -1
- package/dist/server/limits.js +22 -15
- package/dist/server/mounts.d.ts +103 -103
- package/dist/server/mutations/account.js +6 -4
- package/dist/server/mutations/invalidate.js +3 -6
- package/dist/server/mutations/oauth.js +86 -88
- package/dist/server/mutations/refresh.js +45 -87
- package/dist/server/mutations/register.js +19 -19
- package/dist/server/mutations/retrieve.js +17 -15
- package/dist/server/mutations/signature.js +9 -13
- package/dist/server/mutations/signin.js +7 -3
- package/dist/server/mutations/signout.js +10 -15
- package/dist/server/mutations/store.js +22 -12
- package/dist/server/mutations/verifier.js +11 -6
- package/dist/server/mutations/verify.js +55 -46
- package/dist/server/oauth/runtime.js +27 -25
- package/dist/server/passkey.js +299 -250
- package/dist/server/prefetch.js +283 -281
- package/dist/server/refresh.js +7 -60
- package/dist/server/runtime.d.ts +82 -206
- package/dist/server/runtime.js +63 -56
- package/dist/server/services/config.js +5 -3
- package/dist/server/services/logger.js +2 -4
- package/dist/server/services/providers.js +2 -4
- package/dist/server/services/refresh.js +2 -4
- package/dist/server/services/resolve.js +15 -14
- package/dist/server/services/signin.js +2 -4
- package/dist/server/sessions.js +32 -33
- package/dist/server/signin.js +177 -142
- package/dist/server/sso/domain.d.ts +20 -68
- package/dist/server/sso/domain.js +444 -413
- package/dist/server/sso/http.js +53 -59
- package/dist/server/sso/oidc.js +94 -80
- package/dist/server/tokens.js +13 -3
- package/dist/server/totp.js +153 -116
- package/dist/server/types.d.ts +2 -2
- package/dist/server/users.js +18 -23
- package/dist/server/utils/cache.js +51 -0
- package/dist/server/utils/dispatch.js +36 -0
- package/dist/server/utils/retry.js +24 -0
- package/dist/server/utils/span.js +32 -0
- package/dist/shared/errors.js +9 -3
- package/dist/shared/log.js +20 -22
- package/package.json +41 -33
|
@@ -1309,6 +1309,17 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
|
|
|
1309
1309
|
expirationTime: number;
|
|
1310
1310
|
userId: string;
|
|
1311
1311
|
} | null, Name>;
|
|
1312
|
+
sessionIssue: FunctionReference<"mutation", "internal", {
|
|
1313
|
+
refreshTokenExpirationTime?: number;
|
|
1314
|
+
replaceSessionId?: string;
|
|
1315
|
+
sessionExpirationTime: number;
|
|
1316
|
+
sessionId?: string;
|
|
1317
|
+
userId: string;
|
|
1318
|
+
}, {
|
|
1319
|
+
refreshTokenId?: string;
|
|
1320
|
+
sessionId: string;
|
|
1321
|
+
userId: string;
|
|
1322
|
+
}, Name>;
|
|
1312
1323
|
sessionList: FunctionReference<"query", "internal", {
|
|
1313
1324
|
cursor?: string | null;
|
|
1314
1325
|
limit?: number;
|
|
@@ -1343,6 +1354,17 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
|
|
|
1343
1354
|
refreshTokenDeleteAll: FunctionReference<"mutation", "internal", {
|
|
1344
1355
|
sessionId: string;
|
|
1345
1356
|
}, null, Name>;
|
|
1357
|
+
refreshTokenExchange: FunctionReference<"mutation", "internal", {
|
|
1358
|
+
now: number;
|
|
1359
|
+
refreshTokenExpirationTime: number;
|
|
1360
|
+
refreshTokenId: string;
|
|
1361
|
+
reuseWindowMs: number;
|
|
1362
|
+
sessionId: string;
|
|
1363
|
+
}, {
|
|
1364
|
+
refreshTokenId: string;
|
|
1365
|
+
sessionId: string;
|
|
1366
|
+
userId: string;
|
|
1367
|
+
} | null, Name>;
|
|
1346
1368
|
refreshTokenGetActive: FunctionReference<"query", "internal", {
|
|
1347
1369
|
sessionId: string;
|
|
1348
1370
|
}, {
|
|
@@ -1476,6 +1498,7 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
|
|
|
1476
1498
|
verifiers: {
|
|
1477
1499
|
verifierCreate: FunctionReference<"mutation", "internal", {
|
|
1478
1500
|
sessionId?: string;
|
|
1501
|
+
signature?: string;
|
|
1479
1502
|
}, string, Name>;
|
|
1480
1503
|
verifierDelete: FunctionReference<"mutation", "internal", {
|
|
1481
1504
|
verifierId: string;
|
|
@@ -1901,6 +1924,17 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
|
|
|
1901
1924
|
refreshTokenDeleteAll: FunctionReference<"mutation", "internal", {
|
|
1902
1925
|
sessionId: string;
|
|
1903
1926
|
}, null, Name>;
|
|
1927
|
+
refreshTokenExchange: FunctionReference<"mutation", "internal", {
|
|
1928
|
+
now: number;
|
|
1929
|
+
refreshTokenExpirationTime: number;
|
|
1930
|
+
refreshTokenId: string;
|
|
1931
|
+
reuseWindowMs: number;
|
|
1932
|
+
sessionId: string;
|
|
1933
|
+
}, {
|
|
1934
|
+
refreshTokenId: string;
|
|
1935
|
+
sessionId: string;
|
|
1936
|
+
userId: string;
|
|
1937
|
+
} | null, Name>;
|
|
1904
1938
|
refreshTokenGetActive: FunctionReference<"query", "internal", {
|
|
1905
1939
|
sessionId: string;
|
|
1906
1940
|
}, {
|
|
@@ -2122,6 +2156,17 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
|
|
|
2122
2156
|
expirationTime: number;
|
|
2123
2157
|
userId: string;
|
|
2124
2158
|
} | null, Name>;
|
|
2159
|
+
sessionIssue: FunctionReference<"mutation", "internal", {
|
|
2160
|
+
refreshTokenExpirationTime?: number;
|
|
2161
|
+
replaceSessionId?: string;
|
|
2162
|
+
sessionExpirationTime: number;
|
|
2163
|
+
sessionId?: string;
|
|
2164
|
+
userId: string;
|
|
2165
|
+
}, {
|
|
2166
|
+
refreshTokenId?: string;
|
|
2167
|
+
sessionId: string;
|
|
2168
|
+
userId: string;
|
|
2169
|
+
}, Name>;
|
|
2125
2170
|
sessionList: FunctionReference<"query", "internal", {
|
|
2126
2171
|
cursor?: string | null;
|
|
2127
2172
|
limit?: number;
|
|
@@ -2762,6 +2807,7 @@ type ComponentApi<Name extends string | undefined = string | undefined> = {
|
|
|
2762
2807
|
} | null, Name>;
|
|
2763
2808
|
verifierCreate: FunctionReference<"mutation", "internal", {
|
|
2764
2809
|
sessionId?: string;
|
|
2810
|
+
signature?: string;
|
|
2765
2811
|
}, string, Name>;
|
|
2766
2812
|
verifierDelete: FunctionReference<"mutation", "internal", {
|
|
2767
2813
|
verifierId: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthProviderConfig, ConvexAuthConfig, ConvexCredentialsConfig, CorsConfig, DeviceProviderConfig, EmailConfig, EmailUserConfig, GenericDoc, GroupConnectionPolicy, GroupConnectionPolicyPatch, HttpKeyContext,
|
|
1
|
+
import { AuthProviderConfig, ConvexAuthConfig, ConvexCredentialsConfig, CorsConfig, DeviceProviderConfig, EmailConfig, EmailUserConfig, GenericDoc, GroupConnectionPolicy, GroupConnectionPolicyPatch, HttpKeyContext, KeyScope, PhoneConfig, PhoneUserConfig, ScopeChecker } from "../server/types.js";
|
|
2
|
+
import { AuthConfig, AuthContext, AuthContextConfig, InferAuth, OptionalAuthContext, UserDoc } from "../server/auth-context.js";
|
|
2
3
|
import { HttpAuthContext, HttpAuthContextConfig, OptionalHttpAuthContext } from "../server/http.js";
|
|
3
|
-
import { AuthApi,
|
|
4
|
-
export { type AuthApi, type AuthConfig, type AuthContext, type AuthContextConfig, type AuthProviderConfig, type ConvexAuthConfig, type ConvexCredentialsConfig, type CorsConfig, type DeviceProviderConfig, type EmailConfig, type EmailUserConfig, type GenericDoc, type GroupConnectionPolicy, type GroupConnectionPolicyPatch, type HttpAuthContext, type HttpAuthContextConfig, type HttpKeyContext, type InferAuth, type KeyRecord, type KeyScope, type OptionalAuthContext, type OptionalHttpAuthContext, type PhoneConfig, type PhoneUserConfig, type ScopeChecker, type UserDoc, createAuth };
|
|
4
|
+
import { AuthApi, createAuth } from "../server/auth.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as convex_values475 from "convex/values";
|
|
2
2
|
|
|
3
3
|
//#region src/component/model.d.ts
|
|
4
|
-
declare const vApiKeyDoc:
|
|
4
|
+
declare const vApiKeyDoc: convex_values475.VObject<{
|
|
5
5
|
lastUsedAt?: number | undefined;
|
|
6
6
|
expiresAt?: number | undefined;
|
|
7
7
|
rateLimit?: {
|
|
@@ -16,7 +16,7 @@ declare const vApiKeyDoc: convex_values387.VObject<{
|
|
|
16
16
|
_creationTime: number;
|
|
17
17
|
name: string;
|
|
18
18
|
revoked: boolean;
|
|
19
|
-
userId:
|
|
19
|
+
userId: convex_values475.GenericId<"User">;
|
|
20
20
|
prefix: string;
|
|
21
21
|
hashedKey: string;
|
|
22
22
|
scopes: {
|
|
@@ -24,43 +24,43 @@ declare const vApiKeyDoc: convex_values387.VObject<{
|
|
|
24
24
|
actions: string[];
|
|
25
25
|
}[];
|
|
26
26
|
createdAt: number;
|
|
27
|
-
_id:
|
|
27
|
+
_id: convex_values475.GenericId<"ApiKey">;
|
|
28
28
|
}, {
|
|
29
|
-
userId:
|
|
30
|
-
prefix:
|
|
31
|
-
hashedKey:
|
|
32
|
-
name:
|
|
33
|
-
scopes:
|
|
29
|
+
userId: convex_values475.VId<convex_values475.GenericId<"User">, "required">;
|
|
30
|
+
prefix: convex_values475.VString<string, "required">;
|
|
31
|
+
hashedKey: convex_values475.VString<string, "required">;
|
|
32
|
+
name: convex_values475.VString<string, "required">;
|
|
33
|
+
scopes: convex_values475.VArray<{
|
|
34
34
|
resource: string;
|
|
35
35
|
actions: string[];
|
|
36
|
-
}[],
|
|
36
|
+
}[], convex_values475.VObject<{
|
|
37
37
|
resource: string;
|
|
38
38
|
actions: string[];
|
|
39
39
|
}, {
|
|
40
|
-
resource:
|
|
41
|
-
actions:
|
|
40
|
+
resource: convex_values475.VString<string, "required">;
|
|
41
|
+
actions: convex_values475.VArray<string[], convex_values475.VString<string, "required">, "required">;
|
|
42
42
|
}, "required", "resource" | "actions">, "required">;
|
|
43
|
-
rateLimit:
|
|
43
|
+
rateLimit: convex_values475.VObject<{
|
|
44
44
|
maxRequests: number;
|
|
45
45
|
windowMs: number;
|
|
46
46
|
} | undefined, {
|
|
47
|
-
maxRequests:
|
|
48
|
-
windowMs:
|
|
47
|
+
maxRequests: convex_values475.VFloat64<number, "required">;
|
|
48
|
+
windowMs: convex_values475.VFloat64<number, "required">;
|
|
49
49
|
}, "optional", "maxRequests" | "windowMs">;
|
|
50
|
-
rateLimitState:
|
|
50
|
+
rateLimitState: convex_values475.VObject<{
|
|
51
51
|
attemptsLeft: number;
|
|
52
52
|
lastAttemptTime: number;
|
|
53
53
|
} | undefined, {
|
|
54
|
-
attemptsLeft:
|
|
55
|
-
lastAttemptTime:
|
|
54
|
+
attemptsLeft: convex_values475.VFloat64<number, "required">;
|
|
55
|
+
lastAttemptTime: convex_values475.VFloat64<number, "required">;
|
|
56
56
|
}, "optional", "attemptsLeft" | "lastAttemptTime">;
|
|
57
|
-
expiresAt:
|
|
58
|
-
lastUsedAt:
|
|
59
|
-
createdAt:
|
|
60
|
-
revoked:
|
|
61
|
-
metadata:
|
|
62
|
-
_id:
|
|
63
|
-
_creationTime:
|
|
57
|
+
expiresAt: convex_values475.VFloat64<number | undefined, "optional">;
|
|
58
|
+
lastUsedAt: convex_values475.VFloat64<number | undefined, "optional">;
|
|
59
|
+
createdAt: convex_values475.VFloat64<number, "required">;
|
|
60
|
+
revoked: convex_values475.VBoolean<boolean, "required">;
|
|
61
|
+
metadata: convex_values475.VAny<any, "optional", string>;
|
|
62
|
+
_id: convex_values475.VId<convex_values475.GenericId<"ApiKey">, "required">;
|
|
63
|
+
_creationTime: convex_values475.VFloat64<number, "required">;
|
|
64
64
|
}, "required", "_creationTime" | "name" | "revoked" | "lastUsedAt" | "expiresAt" | "userId" | "prefix" | "hashedKey" | "scopes" | "rateLimit" | "rateLimitState" | "createdAt" | "metadata" | "_id" | "rateLimit.maxRequests" | "rateLimit.windowMs" | "rateLimitState.attemptsLeft" | "rateLimitState.lastAttemptTime" | `metadata.${string}`>;
|
|
65
65
|
//#endregion
|
|
66
66
|
export { vApiKeyDoc };
|
|
@@ -99,6 +99,43 @@ const sessionCreate = mutation({
|
|
|
99
99
|
});
|
|
100
100
|
}
|
|
101
101
|
});
|
|
102
|
+
const sessionIssue = mutation({
|
|
103
|
+
args: {
|
|
104
|
+
userId: v.id("User"),
|
|
105
|
+
sessionId: v.optional(v.id("Session")),
|
|
106
|
+
replaceSessionId: v.optional(v.id("Session")),
|
|
107
|
+
sessionExpirationTime: v.number(),
|
|
108
|
+
refreshTokenExpirationTime: v.optional(v.number())
|
|
109
|
+
},
|
|
110
|
+
returns: v.object({
|
|
111
|
+
userId: v.id("User"),
|
|
112
|
+
sessionId: v.id("Session"),
|
|
113
|
+
refreshTokenId: v.optional(v.id("RefreshToken"))
|
|
114
|
+
}),
|
|
115
|
+
handler: async (ctx, args) => {
|
|
116
|
+
let sessionId = args.sessionId;
|
|
117
|
+
if (sessionId === void 0) {
|
|
118
|
+
if (args.replaceSessionId !== void 0) {
|
|
119
|
+
if (await ctx.db.get("Session", args.replaceSessionId) !== null) await ctx.db.delete("Session", args.replaceSessionId);
|
|
120
|
+
const existingTokens = await ctx.db.query("RefreshToken").withIndex("session_id", (q) => q.eq("sessionId", args.replaceSessionId)).collect();
|
|
121
|
+
await Promise.all(existingTokens.map((token) => ctx.db.delete("RefreshToken", token._id)));
|
|
122
|
+
}
|
|
123
|
+
sessionId = await ctx.db.insert("Session", {
|
|
124
|
+
userId: args.userId,
|
|
125
|
+
expirationTime: args.sessionExpirationTime
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
const refreshTokenId = args.refreshTokenExpirationTime === void 0 ? void 0 : await ctx.db.insert("RefreshToken", {
|
|
129
|
+
sessionId,
|
|
130
|
+
expirationTime: args.refreshTokenExpirationTime
|
|
131
|
+
});
|
|
132
|
+
return {
|
|
133
|
+
userId: args.userId,
|
|
134
|
+
sessionId,
|
|
135
|
+
...refreshTokenId === void 0 ? {} : { refreshTokenId }
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
});
|
|
102
139
|
/**
|
|
103
140
|
* Retrieve a single session by its Convex document ID.
|
|
104
141
|
*
|
|
@@ -188,5 +225,5 @@ const sessionListByUser = query({
|
|
|
188
225
|
});
|
|
189
226
|
|
|
190
227
|
//#endregion
|
|
191
|
-
export { sessionCreate, sessionDelete, sessionGetById, sessionList, sessionListByUser };
|
|
228
|
+
export { sessionCreate, sessionDelete, sessionGetById, sessionIssue, sessionList, sessionListByUser };
|
|
192
229
|
//# sourceMappingURL=sessions.js.map
|
|
@@ -159,7 +159,7 @@ const refreshTokenListBySession = query({
|
|
|
159
159
|
args: { sessionId: v.id("Session") },
|
|
160
160
|
returns: v.array(vRefreshTokenDoc),
|
|
161
161
|
handler: async (ctx, { sessionId }) => {
|
|
162
|
-
return await ctx.db.query("RefreshToken").withIndex("
|
|
162
|
+
return await ctx.db.query("RefreshToken").withIndex("session_id", (q) => q.eq("sessionId", sessionId)).collect();
|
|
163
163
|
}
|
|
164
164
|
});
|
|
165
165
|
/**
|
|
@@ -186,11 +186,89 @@ const refreshTokenDeleteAll = mutation({
|
|
|
186
186
|
args: { sessionId: v.id("Session") },
|
|
187
187
|
returns: v.null(),
|
|
188
188
|
handler: async (ctx, { sessionId }) => {
|
|
189
|
-
const tokens = await ctx.db.query("RefreshToken").withIndex("
|
|
189
|
+
const tokens = await ctx.db.query("RefreshToken").withIndex("session_id", (q) => q.eq("sessionId", sessionId)).collect();
|
|
190
190
|
await Promise.all(tokens.map((token) => ctx.db.delete("RefreshToken", token._id)));
|
|
191
191
|
return null;
|
|
192
192
|
}
|
|
193
193
|
});
|
|
194
|
+
const refreshSessionExchangeResult = v.union(v.object({
|
|
195
|
+
userId: v.id("User"),
|
|
196
|
+
sessionId: v.id("Session"),
|
|
197
|
+
refreshTokenId: v.id("RefreshToken")
|
|
198
|
+
}), v.null());
|
|
199
|
+
const refreshTokenExchange = mutation({
|
|
200
|
+
args: {
|
|
201
|
+
refreshTokenId: v.id("RefreshToken"),
|
|
202
|
+
sessionId: v.id("Session"),
|
|
203
|
+
now: v.number(),
|
|
204
|
+
refreshTokenExpirationTime: v.number(),
|
|
205
|
+
reuseWindowMs: v.number()
|
|
206
|
+
},
|
|
207
|
+
returns: refreshSessionExchangeResult,
|
|
208
|
+
handler: async (ctx, args) => {
|
|
209
|
+
const cleanupSessionArtifacts = async () => {
|
|
210
|
+
if (await ctx.db.get("Session", args.sessionId) !== null) await ctx.db.delete("Session", args.sessionId);
|
|
211
|
+
const tokens = await ctx.db.query("RefreshToken").withIndex("session_id", (q) => q.eq("sessionId", args.sessionId)).collect();
|
|
212
|
+
await Promise.all(tokens.map((token) => ctx.db.delete("RefreshToken", token._id)));
|
|
213
|
+
};
|
|
214
|
+
const refreshTokenDoc = await ctx.db.get("RefreshToken", args.refreshTokenId);
|
|
215
|
+
if (refreshTokenDoc === null || refreshTokenDoc.expirationTime < args.now || refreshTokenDoc.sessionId !== args.sessionId) {
|
|
216
|
+
await cleanupSessionArtifacts();
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const session = await ctx.db.get("Session", args.sessionId);
|
|
220
|
+
if (session === null || session.expirationTime < args.now) {
|
|
221
|
+
await cleanupSessionArtifacts();
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
const issueRefreshToken = () => ctx.db.insert("RefreshToken", {
|
|
225
|
+
sessionId: args.sessionId,
|
|
226
|
+
expirationTime: args.refreshTokenExpirationTime,
|
|
227
|
+
parentRefreshTokenId: args.refreshTokenId
|
|
228
|
+
});
|
|
229
|
+
if (refreshTokenDoc.firstUsedTime === void 0) {
|
|
230
|
+
await ctx.db.patch("RefreshToken", args.refreshTokenId, { firstUsedTime: args.now });
|
|
231
|
+
const refreshTokenId = await issueRefreshToken();
|
|
232
|
+
return {
|
|
233
|
+
userId: session.userId,
|
|
234
|
+
sessionId: args.sessionId,
|
|
235
|
+
refreshTokenId
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const activeRefreshToken = await ctx.db.query("RefreshToken").withIndex("session_id_first_used", (q) => q.eq("sessionId", args.sessionId).eq("firstUsedTime", void 0)).order("desc").first();
|
|
239
|
+
if (activeRefreshToken !== null && activeRefreshToken.parentRefreshTokenId === args.refreshTokenId) return {
|
|
240
|
+
userId: session.userId,
|
|
241
|
+
sessionId: args.sessionId,
|
|
242
|
+
refreshTokenId: activeRefreshToken._id
|
|
243
|
+
};
|
|
244
|
+
if (refreshTokenDoc.firstUsedTime + args.reuseWindowMs > args.now) {
|
|
245
|
+
const refreshTokenId = await issueRefreshToken();
|
|
246
|
+
return {
|
|
247
|
+
userId: session.userId,
|
|
248
|
+
sessionId: args.sessionId,
|
|
249
|
+
refreshTokenId
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
const tokensToInvalidate = [refreshTokenDoc];
|
|
253
|
+
const visited = new Set([refreshTokenDoc._id]);
|
|
254
|
+
let frontier = [refreshTokenDoc._id];
|
|
255
|
+
while (frontier.length > 0) {
|
|
256
|
+
const nextFrontier = [];
|
|
257
|
+
for (const parentRefreshTokenId of frontier) {
|
|
258
|
+
const children = await ctx.db.query("RefreshToken").withIndex("session_id_parent_refresh_token_id", (q) => q.eq("sessionId", args.sessionId).eq("parentRefreshTokenId", parentRefreshTokenId)).collect();
|
|
259
|
+
for (const child of children) {
|
|
260
|
+
if (visited.has(child._id)) continue;
|
|
261
|
+
visited.add(child._id);
|
|
262
|
+
tokensToInvalidate.push(child);
|
|
263
|
+
nextFrontier.push(child._id);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
frontier = nextFrontier;
|
|
267
|
+
}
|
|
268
|
+
await Promise.all(tokensToInvalidate.filter((token) => token.firstUsedTime === void 0 || token.firstUsedTime > args.now - args.reuseWindowMs).map((token) => ctx.db.patch("RefreshToken", token._id, { firstUsedTime: args.now - args.reuseWindowMs })));
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
});
|
|
194
272
|
/**
|
|
195
273
|
* Get the active (unused) refresh token for a session.
|
|
196
274
|
*
|
|
@@ -223,5 +301,5 @@ const refreshTokenGetActive = query({
|
|
|
223
301
|
});
|
|
224
302
|
|
|
225
303
|
//#endregion
|
|
226
|
-
export { refreshTokenCreate, refreshTokenDeleteAll, refreshTokenGetActive, refreshTokenGetById, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch };
|
|
304
|
+
export { refreshTokenCreate, refreshTokenDeleteAll, refreshTokenExchange, refreshTokenGetActive, refreshTokenGetById, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch };
|
|
227
305
|
//# sourceMappingURL=tokens.js.map
|
|
@@ -24,10 +24,16 @@ import { v } from "convex/values";
|
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
const verifierCreate = mutation({
|
|
27
|
-
args: {
|
|
27
|
+
args: {
|
|
28
|
+
sessionId: v.optional(v.id("Session")),
|
|
29
|
+
signature: v.optional(v.string())
|
|
30
|
+
},
|
|
28
31
|
returns: v.id("AuthVerifier"),
|
|
29
|
-
handler: async (ctx, { sessionId }) => {
|
|
30
|
-
return await ctx.db.insert("AuthVerifier", {
|
|
32
|
+
handler: async (ctx, { sessionId, signature }) => {
|
|
33
|
+
return await ctx.db.insert("AuthVerifier", {
|
|
34
|
+
sessionId,
|
|
35
|
+
signature
|
|
36
|
+
});
|
|
31
37
|
}
|
|
32
38
|
});
|
|
33
39
|
/**
|
package/dist/component/public.js
CHANGED
|
@@ -12,11 +12,11 @@ import { memberAdd, memberGet, memberGetByGroupAndUser, memberList, memberRemove
|
|
|
12
12
|
import { keyDelete, keyGetByHashedKey, keyGetById, keyInsert, keyList, keyPatch } from "./public/security/keys.js";
|
|
13
13
|
import { passkeyDelete, passkeyGetByCredentialId, passkeyInsert, passkeyListByUserId, passkeyUpdateCounter, passkeyUpdateMeta } from "./public/factors/passkeys.js";
|
|
14
14
|
import { rateLimitCreate, rateLimitDelete, rateLimitGet, rateLimitPatch } from "./public/security/limits.js";
|
|
15
|
-
import { refreshTokenCreate, refreshTokenDeleteAll, refreshTokenGetActive, refreshTokenGetById, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch } from "./public/identity/tokens.js";
|
|
16
|
-
import { sessionCreate, sessionDelete, sessionGetById, sessionList, sessionListByUser } from "./public/identity/sessions.js";
|
|
15
|
+
import { refreshTokenCreate, refreshTokenDeleteAll, refreshTokenExchange, refreshTokenGetActive, refreshTokenGetById, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch } from "./public/identity/tokens.js";
|
|
16
|
+
import { sessionCreate, sessionDelete, sessionGetById, sessionIssue, sessionList, sessionListByUser } from "./public/identity/sessions.js";
|
|
17
17
|
import { totpDelete, totpGetById, totpGetVerifiedByUserId, totpInsert, totpListByUserId, totpMarkVerified, totpUpdateLastUsed } from "./public/factors/totp.js";
|
|
18
18
|
import { userDelete, userFindByVerifiedEmail, userFindByVerifiedPhone, userGetById, userInsert, userList, userPatch, userUpsert } from "./public/identity/users.js";
|
|
19
19
|
import { verificationCodeCreate, verificationCodeDelete, verificationCodeGetByAccountId, verificationCodeGetByCode } from "./public/identity/codes.js";
|
|
20
20
|
import { verifierCreate, verifierDelete, verifierGetById, verifierGetBySignature, verifierPatch } from "./public/identity/verifiers.js";
|
|
21
21
|
|
|
22
|
-
export { accountDelete, accountGet, accountGetById, accountInsert, accountListByUser, accountPatch, deviceAuthorize, deviceDelete, deviceGetByCodeHash, deviceGetByUserCode, deviceInsert, deviceUpdateLastPolled, groupAuditEventCreate, groupAuditEventList, groupConnectionCreate, groupConnectionDelete, groupConnectionDomainAdd, groupConnectionDomainDelete, groupConnectionDomainList, groupConnectionDomainVerificationDelete, groupConnectionDomainVerificationGet, groupConnectionDomainVerificationUpsert, groupConnectionDomainVerify, groupConnectionGet, groupConnectionGetByDomain, groupConnectionList, groupConnectionScimConfigGetByGroupConnection, groupConnectionScimConfigGetByTokenHash, groupConnectionScimConfigUpsert, groupConnectionScimIdentityDelete, groupConnectionScimIdentityGet, groupConnectionScimIdentityGetByGroupConnectionAndUser, groupConnectionScimIdentityGetByMappedGroup, groupConnectionScimIdentityGetByUser, groupConnectionScimIdentityListByGroupConnection, groupConnectionScimIdentityUpsert, groupConnectionSecretDelete, groupConnectionSecretGet, groupConnectionSecretUpsert, groupConnectionUpdate, groupCreate, groupDelete, groupGet, groupList, groupUpdate, groupWebhookDeliveryEnqueue, groupWebhookDeliveryList, groupWebhookDeliveryListReady, groupWebhookDeliveryPatch, groupWebhookEndpointCreate, groupWebhookEndpointGet, groupWebhookEndpointList, groupWebhookEndpointUpdate, inviteAccept, inviteAcceptByToken, inviteCreate, inviteGet, inviteGetByTokenHash, inviteList, inviteRevoke, keyDelete, keyGetByHashedKey, keyGetById, keyInsert, keyList, keyPatch, memberAdd, memberGet, memberGetByGroupAndUser, memberList, memberRemove, memberResolve, memberUpdate, passkeyDelete, passkeyGetByCredentialId, passkeyInsert, passkeyListByUserId, passkeyUpdateCounter, passkeyUpdateMeta, rateLimitCreate, rateLimitDelete, rateLimitGet, rateLimitPatch, refreshTokenCreate, refreshTokenDeleteAll, refreshTokenGetActive, refreshTokenGetById, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch, sessionCreate, sessionDelete, sessionGetById, sessionList, sessionListByUser, totpDelete, totpGetById, totpGetVerifiedByUserId, totpInsert, totpListByUserId, totpMarkVerified, totpUpdateLastUsed, userDelete, userFindByVerifiedEmail, userFindByVerifiedPhone, userGetById, userInsert, userList, userPatch, userUpsert, verificationCodeCreate, verificationCodeDelete, verificationCodeGetByAccountId, verificationCodeGetByCode, verifierCreate, verifierDelete, verifierGetById, verifierGetBySignature, verifierPatch };
|
|
22
|
+
export { accountDelete, accountGet, accountGetById, accountInsert, accountListByUser, accountPatch, deviceAuthorize, deviceDelete, deviceGetByCodeHash, deviceGetByUserCode, deviceInsert, deviceUpdateLastPolled, groupAuditEventCreate, groupAuditEventList, groupConnectionCreate, groupConnectionDelete, groupConnectionDomainAdd, groupConnectionDomainDelete, groupConnectionDomainList, groupConnectionDomainVerificationDelete, groupConnectionDomainVerificationGet, groupConnectionDomainVerificationUpsert, groupConnectionDomainVerify, groupConnectionGet, groupConnectionGetByDomain, groupConnectionList, groupConnectionScimConfigGetByGroupConnection, groupConnectionScimConfigGetByTokenHash, groupConnectionScimConfigUpsert, groupConnectionScimIdentityDelete, groupConnectionScimIdentityGet, groupConnectionScimIdentityGetByGroupConnectionAndUser, groupConnectionScimIdentityGetByMappedGroup, groupConnectionScimIdentityGetByUser, groupConnectionScimIdentityListByGroupConnection, groupConnectionScimIdentityUpsert, groupConnectionSecretDelete, groupConnectionSecretGet, groupConnectionSecretUpsert, groupConnectionUpdate, groupCreate, groupDelete, groupGet, groupList, groupUpdate, groupWebhookDeliveryEnqueue, groupWebhookDeliveryList, groupWebhookDeliveryListReady, groupWebhookDeliveryPatch, groupWebhookEndpointCreate, groupWebhookEndpointGet, groupWebhookEndpointList, groupWebhookEndpointUpdate, inviteAccept, inviteAcceptByToken, inviteCreate, inviteGet, inviteGetByTokenHash, inviteList, inviteRevoke, keyDelete, keyGetByHashedKey, keyGetById, keyInsert, keyList, keyPatch, memberAdd, memberGet, memberGetByGroupAndUser, memberList, memberRemove, memberResolve, memberUpdate, passkeyDelete, passkeyGetByCredentialId, passkeyInsert, passkeyListByUserId, passkeyUpdateCounter, passkeyUpdateMeta, rateLimitCreate, rateLimitDelete, rateLimitGet, rateLimitPatch, refreshTokenCreate, refreshTokenDeleteAll, refreshTokenExchange, refreshTokenGetActive, refreshTokenGetById, refreshTokenGetChildren, refreshTokenListBySession, refreshTokenPatch, sessionCreate, sessionDelete, sessionGetById, sessionIssue, sessionList, sessionListByUser, totpDelete, totpGetById, totpGetVerifiedByUserId, totpInsert, totpListByUserId, totpMarkVerified, totpUpdateLastUsed, userDelete, userFindByVerifiedEmail, userFindByVerifiedPhone, userGetById, userInsert, userList, userPatch, userUpsert, verificationCodeCreate, verificationCodeDelete, verificationCodeGetByAccountId, verificationCodeGetByCode, verifierCreate, verifierDelete, verifierGetById, verifierGetBySignature, verifierPatch };
|