@robelest/convex-auth 0.0.4-preview.29 → 0.0.4-preview.30
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/bin.js +34 -1
- package/dist/browser/passkey.js +2 -2
- package/dist/client/core/types.d.ts +4 -15
- package/dist/client/factors/device.js +3 -3
- package/dist/client/factors/totp.js +8 -8
- package/dist/client/index.js +7 -7
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/model.d.ts +25 -25
- package/dist/component/schema.d.ts +289 -289
- package/dist/core/index.d.ts +5 -24
- package/dist/core/index.js +3 -16
- package/dist/server/auth-context.d.ts +1 -1
- package/dist/server/auth-context.js +14 -1
- package/dist/server/auth.d.ts +3 -17
- package/dist/server/auth.js +2 -7
- package/dist/server/config.js +10 -0
- package/dist/server/context.js +2 -4
- package/dist/server/contract.d.ts +1 -1
- package/dist/server/convexIdentity.d.ts +15 -0
- package/dist/server/convexIdentity.js +1 -0
- package/dist/server/core.js +0 -13
- package/dist/server/device.js +13 -12
- package/dist/server/env.js +10 -2
- package/dist/server/http.d.ts +1 -1
- package/dist/server/identity.js +30 -4
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/mounts.d.ts +79 -79
- package/dist/server/mutations/refresh.js +38 -7
- package/dist/server/mutations/signin.js +12 -2
- package/dist/server/mutations/signout.js +27 -10
- package/dist/server/mutations/store.js +1 -1
- package/dist/server/oauth/factory.js +2 -1
- package/dist/server/passkey.js +12 -13
- package/dist/server/prefetch.js +8 -8
- package/dist/server/runtime.d.ts +19 -25
- package/dist/server/runtime.js +7 -40
- package/dist/server/sessions.d.ts +2 -1
- package/dist/server/sessions.js +21 -11
- package/dist/server/signin.js +17 -16
- package/dist/server/sso/domain.d.ts +1 -1
- package/dist/server/telemetry.js +58 -0
- package/dist/server/tokens.js +24 -4
- package/dist/server/totp.js +13 -11
- package/dist/server/types.d.ts +58 -2
- package/dist/server/utils/span.js +10 -1
- package/dist/shared/authResults.d.ts +16 -0
- package/package.json +6 -3
- package/dist/server/constants.js +0 -6
package/dist/bin.js
CHANGED
|
@@ -6266,7 +6266,7 @@ async function generateKeys() {
|
|
|
6266
6266
|
...publicKey
|
|
6267
6267
|
}] });
|
|
6268
6268
|
return {
|
|
6269
|
-
JWT_PRIVATE_KEY:
|
|
6269
|
+
JWT_PRIVATE_KEY: privateKey.trimEnd(),
|
|
6270
6270
|
JWKS: jwks,
|
|
6271
6271
|
AUTH_SECRET_ENCRYPTION_KEY: randomBytes(32).toString("base64url")
|
|
6272
6272
|
};
|
|
@@ -6506,6 +6506,7 @@ async function runSetup(options) {
|
|
|
6506
6506
|
await configureConvexConfig(config);
|
|
6507
6507
|
await initializeAuth(config);
|
|
6508
6508
|
await initializeAuthCore(config);
|
|
6509
|
+
await initializeAuthConfig(config);
|
|
6509
6510
|
await configureHttp(config);
|
|
6510
6511
|
if (options.variables !== void 0) await configureOtherVariables(config, options.variables);
|
|
6511
6512
|
else printFinalSuccessMessage(config);
|
|
@@ -6819,6 +6820,38 @@ export const auth = createAuthContext(components.auth);
|
|
|
6819
6820
|
O.success(`Created ${newPath}`);
|
|
6820
6821
|
}
|
|
6821
6822
|
}
|
|
6823
|
+
async function initializeAuthConfig(config) {
|
|
6824
|
+
logStep(config, "Initialize auth.config file");
|
|
6825
|
+
const sourceTemplate = `\
|
|
6826
|
+
export default {$$
|
|
6827
|
+
providers: [$$
|
|
6828
|
+
{$$
|
|
6829
|
+
domain: process.env.CONVEX_SITE_URL,$$
|
|
6830
|
+
applicationID: "convex",$$
|
|
6831
|
+
},$$
|
|
6832
|
+
],$$
|
|
6833
|
+
};
|
|
6834
|
+
`;
|
|
6835
|
+
const source = templateToSource(sourceTemplate);
|
|
6836
|
+
const authConfigPath = path.join(config.convexFolderPath, "auth.config");
|
|
6837
|
+
const existingPath = existingNonEmptySourcePath(authConfigPath);
|
|
6838
|
+
if (existingPath !== null) if (doesAlreadyMatchTemplate(readFileSync(existingPath, "utf8"), sourceTemplate)) O.success(`${existingPath} is already set up.`);
|
|
6839
|
+
else {
|
|
6840
|
+
O.info(`You already have ${existingPath}. Make sure it trusts CONVEX_SITE_URL as the Convex auth issuer:`);
|
|
6841
|
+
O.message(indent(`\n${source}\n`));
|
|
6842
|
+
const ready = await ot({ message: "Ready to continue?" });
|
|
6843
|
+
handleCancel(ready);
|
|
6844
|
+
if (!ready) {
|
|
6845
|
+
pt("Setup cancelled.");
|
|
6846
|
+
process$1.exit(1);
|
|
6847
|
+
}
|
|
6848
|
+
}
|
|
6849
|
+
else {
|
|
6850
|
+
const newPath = config.usesTypeScript ? `${authConfigPath}.ts` : `${authConfigPath}.js`;
|
|
6851
|
+
writeFileSync(newPath, source);
|
|
6852
|
+
O.success(`Created ${newPath}`);
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6822
6855
|
async function configureHttp(config) {
|
|
6823
6856
|
logStep(config, "Configure http file");
|
|
6824
6857
|
const sourceTemplate = `\
|
package/dist/browser/passkey.js
CHANGED
|
@@ -8,7 +8,7 @@ function createPasskeyClient(deps) {
|
|
|
8
8
|
if (result.kind !== "signedIn") return { kind: "started" };
|
|
9
9
|
return await setTokenAndMaybeWait(proxy ? {
|
|
10
10
|
shouldStore: false,
|
|
11
|
-
tokens: result.
|
|
11
|
+
tokens: result.session === null ? null : { token: result.session.token },
|
|
12
12
|
waitForHandshake: true,
|
|
13
13
|
context: {
|
|
14
14
|
provider: "passkey",
|
|
@@ -16,7 +16,7 @@ function createPasskeyClient(deps) {
|
|
|
16
16
|
}
|
|
17
17
|
} : {
|
|
18
18
|
shouldStore: true,
|
|
19
|
-
tokens: result.
|
|
19
|
+
tokens: result.session,
|
|
20
20
|
waitForHandshake: true,
|
|
21
21
|
context: {
|
|
22
22
|
provider: "passkey",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AuthTokens, DeviceCodePayload } from "../../shared/authResults.js";
|
|
1
2
|
import { ConvexError, Value } from "convex/values";
|
|
2
3
|
import { FunctionReference } from "convex/server";
|
|
3
4
|
|
|
@@ -76,7 +77,7 @@ interface ClientAdapterDeps {
|
|
|
76
77
|
proxyFetch: (body: Record<string, unknown>) => Promise<unknown>;
|
|
77
78
|
setTokenAndMaybeWait: (args: {
|
|
78
79
|
shouldStore: true;
|
|
79
|
-
tokens:
|
|
80
|
+
tokens: AuthTokens | null;
|
|
80
81
|
waitForHandshake: boolean;
|
|
81
82
|
context: {
|
|
82
83
|
provider?: string;
|
|
@@ -97,28 +98,17 @@ interface ClientAdapterDeps {
|
|
|
97
98
|
interface ClientAdapterFactories {
|
|
98
99
|
passkey?: (deps: ClientAdapterDeps) => PasskeyClient;
|
|
99
100
|
}
|
|
100
|
-
type
|
|
101
|
-
token: string;
|
|
102
|
-
refreshToken: string;
|
|
103
|
-
};
|
|
101
|
+
type DeviceCodeResult = DeviceCodePayload;
|
|
104
102
|
/**
|
|
105
103
|
* Device code response returned when signing in with the `"device"` provider.
|
|
106
104
|
*
|
|
107
105
|
* The device displays the `userCode` (or `verificationUriComplete`) and
|
|
108
106
|
* polls via `auth.device.poll()` until the user authorizes.
|
|
109
107
|
*/
|
|
110
|
-
type DeviceCodeResult = {
|
|
111
|
-
/** High-entropy device code used for polling (keep secret). */deviceCode: string; /** Short human-readable code the user enters (e.g. "WDJB-MJHT"). */
|
|
112
|
-
userCode: string; /** Base verification URL (e.g. "https://myapp.com/device"). */
|
|
113
|
-
verificationUri: string; /** Verification URL with user code pre-filled as `?code=XXXX-XXXX`. */
|
|
114
|
-
verificationUriComplete: string; /** Lifetime of the codes in seconds. */
|
|
115
|
-
expiresIn: number; /** Minimum polling interval in seconds. */
|
|
116
|
-
interval: number;
|
|
117
|
-
};
|
|
118
108
|
/**
|
|
119
109
|
* Result of a `signIn` call.
|
|
120
110
|
*
|
|
121
|
-
* - `kind: "signedIn"` — credentials were accepted and
|
|
111
|
+
* - `kind: "signedIn"` — credentials were accepted and a client session is now available.
|
|
122
112
|
* - `kind: "redirect"` — OAuth flow initiated; redirect the user to `redirect.toString()`.
|
|
123
113
|
* - `kind: "totpRequired"` — credentials valid but 2FA is needed; call `auth.totp.verify()`.
|
|
124
114
|
* - `kind: "deviceCode"` — device flow initiated; display the code and poll via `auth.device.poll()`.
|
|
@@ -163,7 +153,6 @@ type AuthState = {
|
|
|
163
153
|
type AuthApiRefs<HasPasskey extends boolean = boolean, HasTotp extends boolean = boolean, HasDevice extends boolean = boolean> = {
|
|
164
154
|
signIn: FunctionReference<"action", "public", Record<string, Value>, unknown>;
|
|
165
155
|
signOut: FunctionReference<"action", "public", Record<string, Value>, unknown>;
|
|
166
|
-
store: FunctionReference<"mutation", "public", Record<string, Value>, unknown>;
|
|
167
156
|
};
|
|
168
157
|
/**
|
|
169
158
|
* Passkey (WebAuthn) client-side helpers.
|
|
@@ -45,10 +45,10 @@ function createDeviceClient(deps) {
|
|
|
45
45
|
throw error;
|
|
46
46
|
}
|
|
47
47
|
if (pollResult === null) continue;
|
|
48
|
-
if (isSignedInResult(pollResult) && pollResult.
|
|
48
|
+
if (isSignedInResult(pollResult) && pollResult.session) {
|
|
49
49
|
if (proxy) await setTokenAndMaybeWait({
|
|
50
50
|
shouldStore: false,
|
|
51
|
-
tokens: pollResult.
|
|
51
|
+
tokens: pollResult.session === null ? null : { token: pollResult.session.token },
|
|
52
52
|
waitForHandshake: true,
|
|
53
53
|
context: {
|
|
54
54
|
provider: "device",
|
|
@@ -57,7 +57,7 @@ function createDeviceClient(deps) {
|
|
|
57
57
|
});
|
|
58
58
|
else await setTokenAndMaybeWait({
|
|
59
59
|
shouldStore: true,
|
|
60
|
-
tokens: pollResult.
|
|
60
|
+
tokens: pollResult.session ?? null,
|
|
61
61
|
waitForHandshake: true,
|
|
62
62
|
context: {
|
|
63
63
|
provider: "device",
|
|
@@ -56,9 +56,9 @@ function createTotpClient(deps) {
|
|
|
56
56
|
verifier: opts.verifier
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
|
-
if (isSignedInResult(result$1) && result$1.
|
|
59
|
+
if (isSignedInResult(result$1) && result$1.session) await setTokenAndMaybeWait({
|
|
60
60
|
shouldStore: false,
|
|
61
|
-
tokens: result$1.
|
|
61
|
+
tokens: result$1.session === null ? null : { token: result$1.session.token },
|
|
62
62
|
waitForHandshake: true,
|
|
63
63
|
context: {
|
|
64
64
|
provider: "totp",
|
|
@@ -72,9 +72,9 @@ function createTotpClient(deps) {
|
|
|
72
72
|
params,
|
|
73
73
|
verifier: opts.verifier
|
|
74
74
|
});
|
|
75
|
-
if (isSignedInResult(result) && result.
|
|
75
|
+
if (isSignedInResult(result) && result.session) await setTokenAndMaybeWait({
|
|
76
76
|
shouldStore: true,
|
|
77
|
-
tokens: result.
|
|
77
|
+
tokens: result.session ?? null,
|
|
78
78
|
waitForHandshake: true,
|
|
79
79
|
context: {
|
|
80
80
|
provider: "totp",
|
|
@@ -96,9 +96,9 @@ function createTotpClient(deps) {
|
|
|
96
96
|
verifier: opts.verifier
|
|
97
97
|
}
|
|
98
98
|
});
|
|
99
|
-
if (isSignedInResult(result$1) && result$1.
|
|
99
|
+
if (isSignedInResult(result$1) && result$1.session) await setTokenAndMaybeWait({
|
|
100
100
|
shouldStore: false,
|
|
101
|
-
tokens: result$1.
|
|
101
|
+
tokens: result$1.session === null ? null : { token: result$1.session.token },
|
|
102
102
|
waitForHandshake: true,
|
|
103
103
|
context: {
|
|
104
104
|
provider: "totp",
|
|
@@ -112,9 +112,9 @@ function createTotpClient(deps) {
|
|
|
112
112
|
params,
|
|
113
113
|
verifier: opts.verifier
|
|
114
114
|
});
|
|
115
|
-
if (isSignedInResult(result) && result.
|
|
115
|
+
if (isSignedInResult(result) && result.session) await setTokenAndMaybeWait({
|
|
116
116
|
shouldStore: true,
|
|
117
|
-
tokens: result.
|
|
117
|
+
tokens: result.session ?? null,
|
|
118
118
|
waitForHandshake: true,
|
|
119
119
|
context: {
|
|
120
120
|
provider: "totp",
|
package/dist/client/index.js
CHANGED
|
@@ -361,13 +361,13 @@ function client(options) {
|
|
|
361
361
|
const verifyCodeAndSetToken = async (args, opts) => {
|
|
362
362
|
const result = await verifyCode(args);
|
|
363
363
|
if (result.kind !== "signedIn") throw new Error("Code exchange did not return tokens.");
|
|
364
|
-
const {
|
|
364
|
+
const { session } = result;
|
|
365
365
|
await setToken({
|
|
366
366
|
shouldStore: true,
|
|
367
|
-
tokens:
|
|
367
|
+
tokens: session ?? null,
|
|
368
368
|
resyncConvexAuth: opts?.resyncConvexAuth
|
|
369
369
|
});
|
|
370
|
-
return
|
|
370
|
+
return session !== null;
|
|
371
371
|
};
|
|
372
372
|
const normalizeDeviceCodeResult = (device_code) => {
|
|
373
373
|
const input = device_code;
|
|
@@ -441,7 +441,7 @@ function client(options) {
|
|
|
441
441
|
};
|
|
442
442
|
if (result.kind === "signedIn") return await setTokenAndMaybeWait(resultOptions.shouldStore ? {
|
|
443
443
|
shouldStore: true,
|
|
444
|
-
tokens: result.
|
|
444
|
+
tokens: result.session,
|
|
445
445
|
waitForHandshake: true,
|
|
446
446
|
context: {
|
|
447
447
|
provider,
|
|
@@ -449,7 +449,7 @@ function client(options) {
|
|
|
449
449
|
}
|
|
450
450
|
} : {
|
|
451
451
|
shouldStore: false,
|
|
452
|
-
tokens: result.
|
|
452
|
+
tokens: result.session === null ? null : { token: result.session.token },
|
|
453
453
|
waitForHandshake: true,
|
|
454
454
|
context: {
|
|
455
455
|
provider,
|
|
@@ -538,9 +538,9 @@ function client(options) {
|
|
|
538
538
|
action: "auth:signIn",
|
|
539
539
|
args: { refreshToken: true }
|
|
540
540
|
}), isRetriableProxyRefreshError);
|
|
541
|
-
if (isSignedInResult(result) && result.
|
|
541
|
+
if (isSignedInResult(result) && result.session) await setToken({
|
|
542
542
|
shouldStore: false,
|
|
543
|
-
tokens: { token: result.
|
|
543
|
+
tokens: { token: result.session.token },
|
|
544
544
|
resyncConvexAuth: false
|
|
545
545
|
});
|
|
546
546
|
else await setToken({
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as convex_server0 from "convex/server";
|
|
2
2
|
|
|
3
3
|
//#region src/component/convex.config.d.ts
|
|
4
|
-
declare const component:
|
|
4
|
+
declare const component: convex_server0.ComponentDefinition<any>;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { component as default };
|
|
7
7
|
//# sourceMappingURL=convex.config.d.ts.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as convex_values480 from "convex/values";
|
|
2
2
|
|
|
3
3
|
//#region src/component/model.d.ts
|
|
4
|
-
declare const vApiKeyDoc:
|
|
4
|
+
declare const vApiKeyDoc: convex_values480.VObject<{
|
|
5
5
|
lastUsedAt?: number | undefined;
|
|
6
6
|
expiresAt?: number | undefined;
|
|
7
7
|
rateLimit?: {
|
|
@@ -16,7 +16,7 @@ declare const vApiKeyDoc: convex_values478.VObject<{
|
|
|
16
16
|
_creationTime: number;
|
|
17
17
|
name: string;
|
|
18
18
|
revoked: boolean;
|
|
19
|
-
userId:
|
|
19
|
+
userId: convex_values480.GenericId<"User">;
|
|
20
20
|
prefix: string;
|
|
21
21
|
hashedKey: string;
|
|
22
22
|
scopes: {
|
|
@@ -24,43 +24,43 @@ declare const vApiKeyDoc: convex_values478.VObject<{
|
|
|
24
24
|
actions: string[];
|
|
25
25
|
}[];
|
|
26
26
|
createdAt: number;
|
|
27
|
-
_id:
|
|
27
|
+
_id: convex_values480.GenericId<"ApiKey">;
|
|
28
28
|
}, {
|
|
29
|
-
userId:
|
|
30
|
-
prefix:
|
|
31
|
-
hashedKey:
|
|
32
|
-
name:
|
|
33
|
-
scopes:
|
|
29
|
+
userId: convex_values480.VId<convex_values480.GenericId<"User">, "required">;
|
|
30
|
+
prefix: convex_values480.VString<string, "required">;
|
|
31
|
+
hashedKey: convex_values480.VString<string, "required">;
|
|
32
|
+
name: convex_values480.VString<string, "required">;
|
|
33
|
+
scopes: convex_values480.VArray<{
|
|
34
34
|
resource: string;
|
|
35
35
|
actions: string[];
|
|
36
|
-
}[],
|
|
36
|
+
}[], convex_values480.VObject<{
|
|
37
37
|
resource: string;
|
|
38
38
|
actions: string[];
|
|
39
39
|
}, {
|
|
40
|
-
resource:
|
|
41
|
-
actions:
|
|
40
|
+
resource: convex_values480.VString<string, "required">;
|
|
41
|
+
actions: convex_values480.VArray<string[], convex_values480.VString<string, "required">, "required">;
|
|
42
42
|
}, "required", "resource" | "actions">, "required">;
|
|
43
|
-
rateLimit:
|
|
43
|
+
rateLimit: convex_values480.VObject<{
|
|
44
44
|
maxRequests: number;
|
|
45
45
|
windowMs: number;
|
|
46
46
|
} | undefined, {
|
|
47
|
-
maxRequests:
|
|
48
|
-
windowMs:
|
|
47
|
+
maxRequests: convex_values480.VFloat64<number, "required">;
|
|
48
|
+
windowMs: convex_values480.VFloat64<number, "required">;
|
|
49
49
|
}, "optional", "maxRequests" | "windowMs">;
|
|
50
|
-
rateLimitState:
|
|
50
|
+
rateLimitState: convex_values480.VObject<{
|
|
51
51
|
attemptsLeft: number;
|
|
52
52
|
lastAttemptTime: number;
|
|
53
53
|
} | undefined, {
|
|
54
|
-
attemptsLeft:
|
|
55
|
-
lastAttemptTime:
|
|
54
|
+
attemptsLeft: convex_values480.VFloat64<number, "required">;
|
|
55
|
+
lastAttemptTime: convex_values480.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_values480.VFloat64<number | undefined, "optional">;
|
|
58
|
+
lastUsedAt: convex_values480.VFloat64<number | undefined, "optional">;
|
|
59
|
+
createdAt: convex_values480.VFloat64<number, "required">;
|
|
60
|
+
revoked: convex_values480.VBoolean<boolean, "required">;
|
|
61
|
+
metadata: convex_values480.VAny<any, "optional", string>;
|
|
62
|
+
_id: convex_values480.VId<convex_values480.GenericId<"ApiKey">, "required">;
|
|
63
|
+
_creationTime: convex_values480.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 };
|