@robelest/convex-auth 0.0.4-preview.28 → 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 +38 -2
- 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/_generated/component.d.ts +344 -0
- package/dist/component/model.d.ts +25 -25
- package/dist/component/model.js +1 -0
- package/dist/component/public/factors/totp.js +12 -0
- package/dist/component/public/groups/core.js +89 -1
- package/dist/component/public/groups/members.js +39 -1
- package/dist/component/public/identity/accounts.js +22 -3
- package/dist/component/public/identity/users.js +79 -5
- package/dist/component/public/sso/audit.js +5 -2
- package/dist/component/public/sso/core.js +3 -3
- package/dist/component/public/sso/domains.js +7 -3
- package/dist/component/public/sso/scim.js +36 -1
- package/dist/component/public.js +5 -5
- package/dist/component/schema.d.ts +289 -285
- package/dist/component/schema.js +2 -1
- package/dist/core/index.d.ts +52 -35
- package/dist/core/index.js +3 -15
- package/dist/providers/credentials.d.ts +12 -0
- package/dist/providers/password.js +28 -7
- package/dist/server/auth-context.d.ts +18 -1
- package/dist/server/auth-context.js +15 -2
- package/dist/server/auth.d.ts +4 -6
- package/dist/server/auth.js +2 -6
- package/dist/server/config.js +10 -0
- package/dist/server/context.js +13 -9
- package/dist/server/contract.d.ts +1 -1
- package/dist/server/contract.js +44 -12
- package/dist/server/convexIdentity.d.ts +15 -0
- package/dist/server/convexIdentity.js +1 -0
- package/dist/server/core.js +140 -156
- package/dist/server/ctxCache.js +94 -0
- 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/limits.js +39 -9
- package/dist/server/mounts.d.ts +81 -81
- package/dist/server/mutations/credentialsSignIn.js +114 -0
- package/dist/server/mutations/index.js +2 -1
- package/dist/server/mutations/refresh.js +59 -15
- package/dist/server/mutations/retrieve.js +2 -1
- package/dist/server/mutations/signin.js +37 -9
- package/dist/server/mutations/signout.js +27 -10
- package/dist/server/mutations/store.js +6 -1
- package/dist/server/mutations/verify.js +32 -8
- 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 +74 -46
- package/dist/server/runtime.js +7 -40
- package/dist/server/services/group.js +23 -16
- package/dist/server/sessions.d.ts +22 -0
- package/dist/server/sessions.js +52 -32
- package/dist/server/signin.js +48 -24
- package/dist/server/sso/domain.d.ts +1 -1
- package/dist/server/sso/domain.js +1 -2
- package/dist/server/sso/oidc.js +1 -1
- package/dist/server/telemetry.js +58 -0
- package/dist/server/tokens.js +41 -5
- package/dist/server/totp.js +13 -11
- package/dist/server/types.d.ts +58 -2
- package/dist/server/users.js +3 -2
- package/dist/server/utils/span.js +28 -1
- package/dist/shared/authResults.d.ts +16 -0
- package/package.json +6 -3
- package/README.md +0 -161
- package/dist/server/constants.js +0 -6
package/dist/bin.js
CHANGED
|
@@ -6255,7 +6255,10 @@ gradient.pastel = pastel;
|
|
|
6255
6255
|
//#region src/cli/keys.ts
|
|
6256
6256
|
async function generateKeys() {
|
|
6257
6257
|
try {
|
|
6258
|
-
const keys = await generateKeyPair("
|
|
6258
|
+
const keys = await generateKeyPair("EdDSA", {
|
|
6259
|
+
crv: "Ed25519",
|
|
6260
|
+
extractable: true
|
|
6261
|
+
});
|
|
6259
6262
|
const privateKey = await exportPKCS8(keys.privateKey);
|
|
6260
6263
|
const publicKey = await exportJWK(keys.publicKey);
|
|
6261
6264
|
const jwks = JSON.stringify({ keys: [{
|
|
@@ -6263,7 +6266,7 @@ async function generateKeys() {
|
|
|
6263
6266
|
...publicKey
|
|
6264
6267
|
}] });
|
|
6265
6268
|
return {
|
|
6266
|
-
JWT_PRIVATE_KEY:
|
|
6269
|
+
JWT_PRIVATE_KEY: privateKey.trimEnd(),
|
|
6267
6270
|
JWKS: jwks,
|
|
6268
6271
|
AUTH_SECRET_ENCRYPTION_KEY: randomBytes(32).toString("base64url")
|
|
6269
6272
|
};
|
|
@@ -6503,6 +6506,7 @@ async function runSetup(options) {
|
|
|
6503
6506
|
await configureConvexConfig(config);
|
|
6504
6507
|
await initializeAuth(config);
|
|
6505
6508
|
await initializeAuthCore(config);
|
|
6509
|
+
await initializeAuthConfig(config);
|
|
6506
6510
|
await configureHttp(config);
|
|
6507
6511
|
if (options.variables !== void 0) await configureOtherVariables(config, options.variables);
|
|
6508
6512
|
else printFinalSuccessMessage(config);
|
|
@@ -6816,6 +6820,38 @@ export const auth = createAuthContext(components.auth);
|
|
|
6816
6820
|
O.success(`Created ${newPath}`);
|
|
6817
6821
|
}
|
|
6818
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
|
+
}
|
|
6819
6855
|
async function configureHttp(config) {
|
|
6820
6856
|
logStep(config, "Configure http file");
|
|
6821
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({
|