@robelest/convex-auth 0.0.4-preview.21 → 0.0.4-preview.23
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/authorization/index.d.ts +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/authorization/index.js.map +1 -1
- package/dist/client/index.d.ts +1 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +36 -39
- package/dist/client/index.js.map +1 -1
- package/dist/component/client/index.d.ts +1 -2
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/convex.config.d.ts.map +1 -1
- package/dist/component/model.d.ts +5 -5
- package/dist/component/model.d.ts.map +1 -1
- package/dist/component/public/enterprise/audit.d.ts.map +1 -1
- package/dist/component/public/enterprise/audit.js.map +1 -1
- package/dist/component/public/enterprise/core.d.ts.map +1 -1
- package/dist/component/public/enterprise/core.js.map +1 -1
- package/dist/component/public/enterprise/domains.d.ts.map +1 -1
- package/dist/component/public/enterprise/domains.js.map +1 -1
- package/dist/component/public/enterprise/scim.d.ts.map +1 -1
- package/dist/component/public/enterprise/scim.js.map +1 -1
- package/dist/component/public/enterprise/secrets.d.ts.map +1 -1
- package/dist/component/public/enterprise/secrets.js.map +1 -1
- package/dist/component/public/enterprise/webhooks.d.ts.map +1 -1
- package/dist/component/public/enterprise/webhooks.js.map +1 -1
- package/dist/component/public/factors/devices.d.ts.map +1 -1
- package/dist/component/public/factors/devices.js.map +1 -1
- package/dist/component/public/factors/passkeys.d.ts.map +1 -1
- package/dist/component/public/factors/passkeys.js.map +1 -1
- package/dist/component/public/factors/totp.d.ts.map +1 -1
- package/dist/component/public/factors/totp.js.map +1 -1
- package/dist/component/public/groups/core.js.map +1 -1
- package/dist/component/public/groups/invites.d.ts.map +1 -1
- package/dist/component/public/groups/invites.js.map +1 -1
- package/dist/component/public/groups/members.d.ts.map +1 -1
- package/dist/component/public/groups/members.js.map +1 -1
- package/dist/component/public/identity/accounts.d.ts.map +1 -1
- package/dist/component/public/identity/accounts.js.map +1 -1
- package/dist/component/public/identity/codes.d.ts.map +1 -1
- package/dist/component/public/identity/codes.js.map +1 -1
- package/dist/component/public/identity/sessions.d.ts.map +1 -1
- package/dist/component/public/identity/sessions.js.map +1 -1
- package/dist/component/public/identity/tokens.d.ts.map +1 -1
- package/dist/component/public/identity/tokens.js.map +1 -1
- package/dist/component/public/identity/users.d.ts.map +1 -1
- package/dist/component/public/identity/users.js.map +1 -1
- package/dist/component/public/identity/verifiers.d.ts.map +1 -1
- package/dist/component/public/identity/verifiers.js.map +1 -1
- package/dist/component/public/security/keys.d.ts.map +1 -1
- package/dist/component/public/security/keys.js.map +1 -1
- package/dist/component/public/security/limits.d.ts.map +1 -1
- package/dist/component/public/security/limits.js.map +1 -1
- package/dist/component/schema.d.ts +39 -39
- package/dist/component/server/auth.d.ts +95 -52
- package/dist/component/server/auth.d.ts.map +1 -1
- package/dist/component/server/auth.js +63 -43
- package/dist/component/server/auth.js.map +1 -1
- package/dist/component/server/core.js +116 -235
- package/dist/component/server/core.js.map +1 -1
- package/dist/component/server/crypto.js +25 -7
- package/dist/component/server/crypto.js.map +1 -1
- package/dist/component/server/device.js +58 -15
- package/dist/component/server/device.js.map +1 -1
- package/dist/component/server/enterprise/domain.js +148 -59
- package/dist/component/server/enterprise/domain.js.map +1 -1
- package/dist/component/server/enterprise/http.js +36 -15
- package/dist/component/server/enterprise/http.js.map +1 -1
- package/dist/component/server/enterprise/oidc.js +1 -1
- package/dist/component/server/http.js +26 -21
- package/dist/component/server/http.js.map +1 -1
- package/dist/component/server/identity.js +5 -2
- package/dist/component/server/identity.js.map +1 -1
- package/dist/component/server/limits.js +21 -30
- package/dist/component/server/limits.js.map +1 -1
- package/dist/component/server/mutations/account.js +12 -10
- package/dist/component/server/mutations/account.js.map +1 -1
- package/dist/component/server/mutations/code.js +5 -2
- package/dist/component/server/mutations/code.js.map +1 -1
- package/dist/component/server/mutations/invalidate.js +1 -1
- package/dist/component/server/mutations/invalidate.js.map +1 -1
- package/dist/component/server/mutations/oauth.js +10 -4
- package/dist/component/server/mutations/oauth.js.map +1 -1
- package/dist/component/server/mutations/refresh.js +2 -2
- package/dist/component/server/mutations/refresh.js.map +1 -1
- package/dist/component/server/mutations/register.js +46 -42
- package/dist/component/server/mutations/register.js.map +1 -1
- package/dist/component/server/mutations/retrieve.js +21 -25
- package/dist/component/server/mutations/retrieve.js.map +1 -1
- package/dist/component/server/mutations/signature.js +10 -4
- package/dist/component/server/mutations/signature.js.map +1 -1
- package/dist/component/server/mutations/signout.js.map +1 -1
- package/dist/component/server/mutations/store.js +9 -24
- package/dist/component/server/mutations/store.js.map +1 -1
- package/dist/component/server/mutations/verifier.js.map +1 -1
- package/dist/component/server/mutations/verify.js +1 -1
- package/dist/component/server/mutations/verify.js.map +1 -1
- package/dist/component/server/oauth.js +53 -16
- package/dist/component/server/oauth.js.map +1 -1
- package/dist/component/server/passkey.js +115 -31
- package/dist/component/server/passkey.js.map +1 -1
- package/dist/component/server/redirects.js +9 -3
- package/dist/component/server/redirects.js.map +1 -1
- package/dist/component/server/refresh.js +10 -7
- package/dist/component/server/refresh.js.map +1 -1
- package/dist/component/server/runtime.d.ts +3 -3
- package/dist/component/server/runtime.d.ts.map +1 -1
- package/dist/component/server/runtime.js +62 -20
- package/dist/component/server/runtime.js.map +1 -1
- package/dist/component/server/signin.js +34 -10
- package/dist/component/server/signin.js.map +1 -1
- package/dist/component/server/totp.js +79 -19
- package/dist/component/server/totp.js.map +1 -1
- package/dist/component/server/types.d.ts +12 -20
- package/dist/component/server/types.d.ts.map +1 -1
- package/dist/component/server/types.js.map +1 -1
- package/dist/component/server/users.js +6 -3
- package/dist/component/server/users.js.map +1 -1
- package/dist/component/server/utils.js +10 -4
- package/dist/component/server/utils.js.map +1 -1
- package/dist/core/types.d.ts +14 -22
- package/dist/core/types.d.ts.map +1 -1
- package/dist/factors/device.js +8 -9
- package/dist/factors/device.js.map +1 -1
- package/dist/factors/passkey.js +18 -21
- package/dist/factors/passkey.js.map +1 -1
- package/dist/providers/password.js +66 -81
- package/dist/providers/password.js.map +1 -1
- package/dist/runtime/invite.js +2 -8
- package/dist/runtime/invite.js.map +1 -1
- package/dist/server/auth.d.ts +95 -52
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +63 -43
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core.d.ts +71 -159
- package/dist/server/core.d.ts.map +1 -1
- package/dist/server/core.js +116 -235
- package/dist/server/core.js.map +1 -1
- package/dist/server/crypto.d.ts.map +1 -1
- package/dist/server/crypto.js +25 -7
- package/dist/server/crypto.js.map +1 -1
- package/dist/server/device.js +58 -15
- package/dist/server/device.js.map +1 -1
- package/dist/server/enterprise/domain.d.ts +0 -8
- package/dist/server/enterprise/domain.d.ts.map +1 -1
- package/dist/server/enterprise/domain.js +148 -59
- package/dist/server/enterprise/domain.js.map +1 -1
- package/dist/server/enterprise/http.d.ts.map +1 -1
- package/dist/server/enterprise/http.js +35 -14
- package/dist/server/enterprise/http.js.map +1 -1
- package/dist/server/http.d.ts +2 -2
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +25 -20
- package/dist/server/http.js.map +1 -1
- package/dist/server/identity.js +5 -2
- package/dist/server/identity.js.map +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/server/limits.js +21 -30
- package/dist/server/limits.js.map +1 -1
- package/dist/server/mounts.d.ts +26 -64
- package/dist/server/mounts.d.ts.map +1 -1
- package/dist/server/mounts.js +45 -106
- package/dist/server/mounts.js.map +1 -1
- package/dist/server/mutations/account.d.ts +8 -9
- package/dist/server/mutations/account.d.ts.map +1 -1
- package/dist/server/mutations/account.js +11 -9
- package/dist/server/mutations/account.js.map +1 -1
- package/dist/server/mutations/code.d.ts +13 -13
- package/dist/server/mutations/code.d.ts.map +1 -1
- package/dist/server/mutations/code.js +5 -2
- package/dist/server/mutations/code.js.map +1 -1
- package/dist/server/mutations/invalidate.d.ts +4 -4
- package/dist/server/mutations/invalidate.d.ts.map +1 -1
- package/dist/server/mutations/invalidate.js.map +1 -1
- package/dist/server/mutations/oauth.d.ts +12 -10
- package/dist/server/mutations/oauth.d.ts.map +1 -1
- package/dist/server/mutations/oauth.js +9 -3
- package/dist/server/mutations/oauth.js.map +1 -1
- package/dist/server/mutations/refresh.d.ts +3 -3
- package/dist/server/mutations/refresh.d.ts.map +1 -1
- package/dist/server/mutations/refresh.js +1 -1
- package/dist/server/mutations/refresh.js.map +1 -1
- package/dist/server/mutations/register.d.ts +11 -11
- package/dist/server/mutations/register.d.ts.map +1 -1
- package/dist/server/mutations/register.js +45 -41
- package/dist/server/mutations/register.js.map +1 -1
- package/dist/server/mutations/retrieve.d.ts +6 -6
- package/dist/server/mutations/retrieve.d.ts.map +1 -1
- package/dist/server/mutations/retrieve.js +20 -24
- package/dist/server/mutations/retrieve.js.map +1 -1
- package/dist/server/mutations/signature.d.ts +6 -7
- package/dist/server/mutations/signature.d.ts.map +1 -1
- package/dist/server/mutations/signature.js +9 -3
- package/dist/server/mutations/signature.js.map +1 -1
- package/dist/server/mutations/signin.d.ts +5 -5
- package/dist/server/mutations/signin.d.ts.map +1 -1
- package/dist/server/mutations/signout.js.map +1 -1
- package/dist/server/mutations/store.d.ts +97 -97
- package/dist/server/mutations/store.d.ts.map +1 -1
- package/dist/server/mutations/store.js +8 -23
- package/dist/server/mutations/store.js.map +1 -1
- package/dist/server/mutations/verifier.js.map +1 -1
- package/dist/server/mutations/verify.d.ts +10 -10
- package/dist/server/mutations/verify.d.ts.map +1 -1
- package/dist/server/mutations/verify.js.map +1 -1
- package/dist/server/oauth.js +53 -16
- package/dist/server/oauth.js.map +1 -1
- package/dist/server/passkey.d.ts +2 -2
- package/dist/server/passkey.d.ts.map +1 -1
- package/dist/server/passkey.js +114 -30
- package/dist/server/passkey.js.map +1 -1
- package/dist/server/redirects.js +9 -3
- package/dist/server/redirects.js.map +1 -1
- package/dist/server/refresh.js +10 -7
- package/dist/server/refresh.js.map +1 -1
- package/dist/server/runtime.d.ts +14 -14
- package/dist/server/runtime.d.ts.map +1 -1
- package/dist/server/runtime.js +61 -19
- package/dist/server/runtime.js.map +1 -1
- package/dist/server/signin.js +34 -10
- package/dist/server/signin.js.map +1 -1
- package/dist/server/ssr.d.ts.map +1 -1
- package/dist/server/ssr.js +175 -184
- package/dist/server/ssr.js.map +1 -1
- package/dist/server/totp.js +78 -18
- package/dist/server/totp.js.map +1 -1
- package/dist/server/types.d.ts +13 -21
- package/dist/server/types.d.ts.map +1 -1
- package/dist/server/types.js.map +1 -1
- package/dist/server/users.js +6 -3
- package/dist/server/users.js.map +1 -1
- package/dist/server/utils.js +10 -4
- package/dist/server/utils.js.map +1 -1
- package/package.json +2 -6
- package/src/authorization/index.ts +1 -1
- package/src/cli/index.ts +1 -1
- package/src/client/core/types.ts +14 -14
- package/src/client/factors/device.ts +10 -12
- package/src/client/factors/passkey.ts +23 -26
- package/src/client/index.ts +54 -64
- package/src/client/runtime/invite.ts +5 -7
- package/src/component/index.ts +1 -0
- package/src/component/public/enterprise/audit.ts +6 -1
- package/src/component/public/enterprise/core.ts +1 -0
- package/src/component/public/enterprise/domains.ts +5 -1
- package/src/component/public/enterprise/scim.ts +1 -0
- package/src/component/public/enterprise/secrets.ts +1 -0
- package/src/component/public/enterprise/webhooks.ts +1 -0
- package/src/component/public/factors/devices.ts +1 -0
- package/src/component/public/factors/passkeys.ts +1 -0
- package/src/component/public/factors/totp.ts +1 -0
- package/src/component/public/groups/core.ts +1 -1
- package/src/component/public/groups/invites.ts +7 -1
- package/src/component/public/groups/members.ts +1 -0
- package/src/component/public/identity/accounts.ts +1 -0
- package/src/component/public/identity/codes.ts +1 -0
- package/src/component/public/identity/sessions.ts +1 -0
- package/src/component/public/identity/tokens.ts +1 -0
- package/src/component/public/identity/users.ts +1 -0
- package/src/component/public/identity/verifiers.ts +1 -0
- package/src/component/public/security/keys.ts +1 -0
- package/src/component/public/security/limits.ts +1 -0
- package/src/providers/password.ts +89 -110
- package/src/server/auth.ts +177 -111
- package/src/server/core.ts +197 -233
- package/src/server/crypto.ts +31 -29
- package/src/server/device.ts +65 -32
- package/src/server/enterprise/domain.ts +158 -170
- package/src/server/enterprise/http.ts +46 -39
- package/src/server/http.ts +36 -30
- package/src/server/identity.ts +5 -5
- package/src/server/index.ts +2 -0
- package/src/server/limits.ts +53 -80
- package/src/server/mounts.ts +47 -74
- package/src/server/mutations/account.ts +22 -36
- package/src/server/mutations/code.ts +6 -6
- package/src/server/mutations/invalidate.ts +1 -1
- package/src/server/mutations/oauth.ts +14 -8
- package/src/server/mutations/refresh.ts +5 -4
- package/src/server/mutations/register.ts +87 -132
- package/src/server/mutations/retrieve.ts +44 -44
- package/src/server/mutations/signature.ts +13 -6
- package/src/server/mutations/signout.ts +1 -1
- package/src/server/mutations/store.ts +16 -31
- package/src/server/mutations/verifier.ts +1 -1
- package/src/server/mutations/verify.ts +3 -5
- package/src/server/oauth.ts +60 -69
- package/src/server/passkey.ts +567 -517
- package/src/server/redirects.ts +10 -6
- package/src/server/refresh.ts +14 -18
- package/src/server/runtime.ts +70 -55
- package/src/server/signin.ts +44 -37
- package/src/server/ssr.ts +390 -407
- package/src/server/totp.ts +85 -35
- package/src/server/types.ts +19 -22
- package/src/server/users.ts +7 -6
- package/src/server/utils.ts +10 -12
- package/dist/component/server/authError.js +0 -34
- package/dist/component/server/authError.js.map +0 -1
- package/dist/component/server/errors.d.ts +0 -1
- package/dist/component/server/errors.js +0 -137
- package/dist/component/server/errors.js.map +0 -1
- package/dist/server/authError.d.ts +0 -46
- package/dist/server/authError.d.ts.map +0 -1
- package/dist/server/authError.js +0 -34
- package/dist/server/authError.js.map +0 -1
- package/dist/server/errors.d.ts +0 -177
- package/dist/server/errors.d.ts.map +0 -1
- package/dist/server/errors.js +0 -212
- package/dist/server/errors.js.map +0 -1
- package/src/server/authError.ts +0 -44
- package/src/server/errors.ts +0 -290
package/src/server/redirects.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cv } from "@robelest/fx/convex";
|
|
2
|
+
|
|
2
3
|
import { ConvexAuthMaterializedConfig } from "./types";
|
|
3
4
|
import { requireEnv } from "./utils";
|
|
4
5
|
|
|
@@ -11,17 +12,20 @@ export async function redirectAbsoluteUrl(
|
|
|
11
12
|
return requireEnv("SITE_URL").replace(/\/$/, "");
|
|
12
13
|
}
|
|
13
14
|
if (typeof params.redirectTo !== "string") {
|
|
14
|
-
throw
|
|
15
|
-
"INVALID_REDIRECT",
|
|
16
|
-
`Expected \`redirectTo\` to be a string, got ${params.redirectTo as any}`,
|
|
17
|
-
);
|
|
15
|
+
throw Cv.error({
|
|
16
|
+
code: "INVALID_REDIRECT",
|
|
17
|
+
message: `Expected \`redirectTo\` to be a string, got ${params.redirectTo as any}`,
|
|
18
|
+
});
|
|
18
19
|
}
|
|
19
20
|
const redirectCallback =
|
|
20
21
|
config.callbacks?.redirect ?? defaultRedirectCallback;
|
|
21
22
|
try {
|
|
22
23
|
return await redirectCallback({ redirectTo: params.redirectTo });
|
|
23
24
|
} catch {
|
|
24
|
-
throw
|
|
25
|
+
throw Cv.error({
|
|
26
|
+
code: "INTERNAL_ERROR",
|
|
27
|
+
message: "An unexpected error occurred.",
|
|
28
|
+
});
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
|
package/src/server/refresh.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Fx } from "@robelest/fx";
|
|
2
|
-
import {
|
|
2
|
+
import { Cv } from "@robelest/fx/convex";
|
|
3
|
+
import { ConvexError, GenericId } from "convex/values";
|
|
3
4
|
|
|
4
5
|
import { authDb } from "./db";
|
|
5
|
-
import { AuthError } from "./authError";
|
|
6
6
|
import { Doc, MutationCtx } from "./types";
|
|
7
7
|
import { ConvexAuthConfig } from "./types";
|
|
8
8
|
import {
|
|
@@ -56,21 +56,19 @@ export const parseRefreshToken = (
|
|
|
56
56
|
refreshTokenId: GenericId<"RefreshToken">;
|
|
57
57
|
sessionId: GenericId<"Session">;
|
|
58
58
|
},
|
|
59
|
-
|
|
59
|
+
ConvexError<any>
|
|
60
60
|
> => {
|
|
61
61
|
const [refreshTokenId, sessionId] = refreshToken.split(REFRESH_TOKEN_DIVIDER);
|
|
62
62
|
const msg = `Can't parse refresh token: ${maybeRedact(refreshToken)}`;
|
|
63
|
-
const refreshTokenIdFx: Fx<string,
|
|
64
|
-
refreshTokenId
|
|
65
|
-
|
|
66
|
-
: Fx.fail(new AuthError("INVALID_REFRESH_TOKEN", msg));
|
|
63
|
+
const refreshTokenIdFx: Fx<string, ConvexError<any>> = refreshTokenId != null
|
|
64
|
+
? Fx.succeed(refreshTokenId)
|
|
65
|
+
: Cv.fail({ code: "INVALID_REFRESH_TOKEN", message: msg });
|
|
67
66
|
|
|
68
67
|
return refreshTokenIdFx.pipe(
|
|
69
68
|
Fx.chain((rtId) => {
|
|
70
|
-
const sessionIdFx: Fx<string,
|
|
71
|
-
sessionId
|
|
72
|
-
|
|
73
|
-
: Fx.fail(new AuthError("INVALID_REFRESH_TOKEN", msg));
|
|
69
|
+
const sessionIdFx: Fx<string, ConvexError<any>> = sessionId != null
|
|
70
|
+
? Fx.succeed(sessionId)
|
|
71
|
+
: Cv.fail({ code: "INVALID_REFRESH_TOKEN", message: msg });
|
|
74
72
|
return sessionIdFx.pipe(
|
|
75
73
|
Fx.map((sId) => ({
|
|
76
74
|
refreshTokenId: rtId as GenericId<"RefreshToken">,
|
|
@@ -115,13 +113,11 @@ export async function invalidateRefreshTokensInSubtree(
|
|
|
115
113
|
Fx.each(tokensToInvalidate, (token) =>
|
|
116
114
|
token.firstUsedTime === undefined ||
|
|
117
115
|
token.firstUsedTime > Date.now() - REFRESH_TOKEN_REUSE_WINDOW_MS
|
|
118
|
-
? Fx.
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
err: (e) => e as never,
|
|
124
|
-
})
|
|
116
|
+
? Fx.promise(() =>
|
|
117
|
+
db.refreshTokens.patch(token._id, {
|
|
118
|
+
firstUsedTime: Date.now() - REFRESH_TOKEN_REUSE_WINDOW_MS,
|
|
119
|
+
}),
|
|
120
|
+
)
|
|
125
121
|
: Fx.unit,
|
|
126
122
|
),
|
|
127
123
|
);
|
package/src/server/runtime.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { Fx } from "@robelest/fx";
|
|
2
|
+
import { Cv } from "@robelest/fx/convex";
|
|
1
3
|
import {
|
|
2
|
-
Auth,
|
|
3
4
|
GenericActionCtx,
|
|
4
5
|
GenericDataModel,
|
|
5
6
|
HttpRouter,
|
|
@@ -9,10 +10,10 @@ import {
|
|
|
9
10
|
import { v } from "convex/values";
|
|
10
11
|
import { serialize as serializeCookie } from "cookie";
|
|
11
12
|
|
|
12
|
-
import {
|
|
13
|
+
import { configDefaults, listAvailableProviders } from "./config";
|
|
13
14
|
import { redirectToParamCookie, useRedirectToParam } from "./cookies";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
15
|
+
import { createCoreDomains } from "./core";
|
|
16
|
+
import { GetProviderOrThrowFunc } from "./crypto";
|
|
16
17
|
import {
|
|
17
18
|
getOidcConfig,
|
|
18
19
|
getPublicOidcConfig,
|
|
@@ -20,24 +21,24 @@ import {
|
|
|
20
21
|
upsertProtocolConfig,
|
|
21
22
|
withOidcSecretState,
|
|
22
23
|
} from "./enterprise/config";
|
|
23
|
-
import {
|
|
24
|
+
import { createEnterpriseDomain } from "./enterprise/domain";
|
|
25
|
+
import { addEnterpriseHttpRuntime } from "./enterprise/http";
|
|
26
|
+
import {
|
|
27
|
+
normalizeEnterprisePolicy,
|
|
28
|
+
patchEnterprisePolicy,
|
|
29
|
+
} from "./enterprise/policy";
|
|
24
30
|
import {
|
|
25
31
|
createServiceProviderMetadata,
|
|
26
32
|
getSamlServiceProviderOptions,
|
|
27
33
|
parseSamlIdpMetadata,
|
|
28
34
|
} from "./enterprise/saml";
|
|
29
|
-
import {
|
|
30
|
-
parseScimPath,
|
|
31
|
-
} from "./enterprise/scim";
|
|
35
|
+
import { parseScimPath } from "./enterprise/scim";
|
|
32
36
|
import {
|
|
33
37
|
enterpriseOidcProviderId,
|
|
34
38
|
getEnterpriseOidcUrls,
|
|
35
39
|
isEnterpriseSamlSourceActive,
|
|
36
40
|
normalizeDomain,
|
|
37
41
|
} from "./enterprise/shared";
|
|
38
|
-
import { Fx } from "@robelest/fx";
|
|
39
|
-
|
|
40
|
-
import { AuthError } from "./authError";
|
|
41
42
|
import {
|
|
42
43
|
addAuthRoutes,
|
|
43
44
|
addOpenIdRoutes,
|
|
@@ -58,8 +59,6 @@ import {
|
|
|
58
59
|
storeImpl,
|
|
59
60
|
} from "./mutations/index";
|
|
60
61
|
import { createOAuthAuthorizationURL, handleOAuthCallback } from "./oauth";
|
|
61
|
-
import { GetProviderOrThrowFunc } from "./crypto";
|
|
62
|
-
import { configDefaults, listAvailableProviders } from "./config";
|
|
63
62
|
import { redirectAbsoluteUrl, setURLSearchParam } from "./redirects";
|
|
64
63
|
import { signInImpl } from "./signin";
|
|
65
64
|
import type {
|
|
@@ -171,9 +170,11 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
171
170
|
`Provider \`${id}\` is not configured, ` +
|
|
172
171
|
`available providers are ${listAvailableProviders(config, allowExtraProviders)}.`;
|
|
173
172
|
logWithLevel(LOG_LEVELS.ERROR, detail);
|
|
174
|
-
throw
|
|
173
|
+
throw Cv.error({
|
|
174
|
+
code: "PROVIDER_NOT_CONFIGURED",
|
|
175
|
+
message: detail,
|
|
175
176
|
provider: id,
|
|
176
|
-
})
|
|
177
|
+
});
|
|
177
178
|
}
|
|
178
179
|
return provider;
|
|
179
180
|
};
|
|
@@ -231,10 +232,10 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
231
232
|
},
|
|
232
233
|
);
|
|
233
234
|
if (!enterprise) {
|
|
234
|
-
throw
|
|
235
|
-
"INVALID_PARAMETERS",
|
|
236
|
-
enterpriseNotFoundError,
|
|
237
|
-
)
|
|
235
|
+
throw Cv.error({
|
|
236
|
+
code: "INVALID_PARAMETERS",
|
|
237
|
+
message: enterpriseNotFoundError,
|
|
238
|
+
});
|
|
238
239
|
}
|
|
239
240
|
return enterprise;
|
|
240
241
|
};
|
|
@@ -245,10 +246,10 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
245
246
|
) => {
|
|
246
247
|
const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);
|
|
247
248
|
if (enterprise.status !== "active") {
|
|
248
|
-
throw
|
|
249
|
-
"INVALID_PARAMETERS",
|
|
250
|
-
"Enterprise connection is not active.",
|
|
251
|
-
)
|
|
249
|
+
throw Cv.error({
|
|
250
|
+
code: "INVALID_PARAMETERS",
|
|
251
|
+
message: "Enterprise connection is not active.",
|
|
252
|
+
});
|
|
252
253
|
}
|
|
253
254
|
return enterprise;
|
|
254
255
|
};
|
|
@@ -268,17 +269,17 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
268
269
|
enterprise,
|
|
269
270
|
};
|
|
270
271
|
if (!isEnterpriseSamlSourceActive(loaded)) {
|
|
271
|
-
throw
|
|
272
|
-
"INVALID_PARAMETERS",
|
|
273
|
-
"Enterprise connection is not active.",
|
|
274
|
-
)
|
|
272
|
+
throw Cv.error({
|
|
273
|
+
code: "INVALID_PARAMETERS",
|
|
274
|
+
message: "Enterprise connection is not active.",
|
|
275
|
+
});
|
|
275
276
|
}
|
|
276
277
|
const saml = getSamlConfig(loaded.config);
|
|
277
278
|
if (!saml.idp?.metadataXml) {
|
|
278
|
-
throw
|
|
279
|
-
"PROVIDER_NOT_CONFIGURED",
|
|
280
|
-
"SAML is not configured for this enterprise.",
|
|
281
|
-
)
|
|
279
|
+
throw Cv.error({
|
|
280
|
+
code: "PROVIDER_NOT_CONFIGURED",
|
|
281
|
+
message: "SAML is not configured for this enterprise.",
|
|
282
|
+
});
|
|
282
283
|
}
|
|
283
284
|
return { loaded, enterprise, saml };
|
|
284
285
|
};
|
|
@@ -290,10 +291,10 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
290
291
|
const enterprise = await loadActiveEnterpriseOrThrow(ctx, enterpriseId);
|
|
291
292
|
const oidc = await getEnterpriseOidcConfigWithSecret(ctx, enterprise);
|
|
292
293
|
if (oidc.enabled !== true) {
|
|
293
|
-
throw
|
|
294
|
-
"PROVIDER_NOT_CONFIGURED",
|
|
295
|
-
"OIDC is not configured for this enterprise.",
|
|
296
|
-
)
|
|
294
|
+
throw Cv.error({
|
|
295
|
+
code: "PROVIDER_NOT_CONFIGURED",
|
|
296
|
+
message: "OIDC is not configured for this enterprise.",
|
|
297
|
+
});
|
|
297
298
|
}
|
|
298
299
|
return { enterprise, oidc };
|
|
299
300
|
};
|
|
@@ -407,7 +408,10 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
407
408
|
) => {
|
|
408
409
|
const authHeader = request.headers.get("Authorization");
|
|
409
410
|
if (!authHeader?.startsWith("Bearer ")) {
|
|
410
|
-
throw
|
|
411
|
+
throw Cv.error({
|
|
412
|
+
code: "MISSING_BEARER_TOKEN",
|
|
413
|
+
message: "Missing or malformed Authorization: Bearer header.",
|
|
414
|
+
});
|
|
411
415
|
}
|
|
412
416
|
const token = authHeader.slice(7);
|
|
413
417
|
const scimConfig = await ctx.runQuery(
|
|
@@ -415,17 +419,17 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
415
419
|
{ tokenHash: await sha256(token) },
|
|
416
420
|
);
|
|
417
421
|
if (!scimConfig || scimConfig.status !== "active") {
|
|
418
|
-
throw
|
|
419
|
-
"INVALID_API_KEY",
|
|
420
|
-
"Invalid SCIM token.",
|
|
421
|
-
)
|
|
422
|
+
throw Cv.error({
|
|
423
|
+
code: "INVALID_API_KEY",
|
|
424
|
+
message: "Invalid SCIM token.",
|
|
425
|
+
});
|
|
422
426
|
}
|
|
423
427
|
const parsedPath = parseScimPath(new URL(request.url).pathname);
|
|
424
428
|
if (parsedPath.enterpriseId !== scimConfig.enterpriseId) {
|
|
425
|
-
throw
|
|
426
|
-
"INVALID_API_KEY",
|
|
427
|
-
"SCIM token/tenant mismatch.",
|
|
428
|
-
)
|
|
429
|
+
throw Cv.error({
|
|
430
|
+
code: "INVALID_API_KEY",
|
|
431
|
+
message: "SCIM token/tenant mismatch.",
|
|
432
|
+
});
|
|
429
433
|
}
|
|
430
434
|
const enterprise = await ctx.runQuery(
|
|
431
435
|
config.component.public.enterpriseGet,
|
|
@@ -434,10 +438,10 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
434
438
|
},
|
|
435
439
|
);
|
|
436
440
|
if (enterprise === null) {
|
|
437
|
-
throw
|
|
438
|
-
"INVALID_PARAMETERS",
|
|
439
|
-
"Enterprise not found.",
|
|
440
|
-
)
|
|
441
|
+
throw Cv.error({
|
|
442
|
+
code: "INVALID_PARAMETERS",
|
|
443
|
+
message: "Enterprise not found.",
|
|
444
|
+
});
|
|
441
445
|
}
|
|
442
446
|
return { scimConfig, enterprise, parsedPath };
|
|
443
447
|
};
|
|
@@ -548,13 +552,19 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
548
552
|
handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {
|
|
549
553
|
const url = new URL(request.url);
|
|
550
554
|
const pathParts = url.pathname.split("/");
|
|
551
|
-
const providerId = pathParts.
|
|
555
|
+
const providerId = pathParts[pathParts.length - 1]!;
|
|
552
556
|
if (providerId === null) {
|
|
553
|
-
throw
|
|
557
|
+
throw Cv.error({
|
|
558
|
+
code: "OAUTH_MISSING_PROVIDER",
|
|
559
|
+
message: "Missing OAuth provider ID.",
|
|
560
|
+
});
|
|
554
561
|
}
|
|
555
562
|
const verifier = url.searchParams.get("code");
|
|
556
563
|
if (verifier === null) {
|
|
557
|
-
throw
|
|
564
|
+
throw Cv.error({
|
|
565
|
+
code: "OAUTH_MISSING_VERIFIER",
|
|
566
|
+
message: "Missing sign-in verifier.",
|
|
567
|
+
});
|
|
558
568
|
}
|
|
559
569
|
const provider = getProviderOrThrow(providerId);
|
|
560
570
|
|
|
@@ -588,11 +598,16 @@ export function Auth(config_: ConvexAuthConfig) {
|
|
|
588
598
|
}),
|
|
589
599
|
handleCallback: async (ctx, request) => {
|
|
590
600
|
const url = new URL(request.url);
|
|
591
|
-
const
|
|
592
|
-
|
|
593
|
-
|
|
601
|
+
const callbackPathParts = new URL(request.url).pathname.split(
|
|
602
|
+
"/",
|
|
603
|
+
);
|
|
604
|
+
const providerId =
|
|
605
|
+
callbackPathParts[callbackPathParts.length - 1];
|
|
594
606
|
if (!providerId) {
|
|
595
|
-
throw
|
|
607
|
+
throw Cv.error({
|
|
608
|
+
code: "OAUTH_MISSING_PROVIDER",
|
|
609
|
+
message: "Missing OAuth provider ID.",
|
|
610
|
+
});
|
|
596
611
|
}
|
|
597
612
|
logWithLevel(
|
|
598
613
|
LOG_LEVELS.DEBUG,
|
package/src/server/signin.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Fx as FxType } from "@robelest/fx";
|
|
2
|
+
import { Fx } from "@robelest/fx";
|
|
3
|
+
import { Cv } from "@robelest/fx/convex";
|
|
2
4
|
import { GenericId } from "convex/values";
|
|
5
|
+
import { ConvexError } from "convex/values";
|
|
3
6
|
|
|
4
7
|
import { handleDevice } from "./device";
|
|
5
|
-
import { Fx } from "@robelest/fx";
|
|
6
|
-
|
|
7
|
-
import { AuthError } from "./authError";
|
|
8
8
|
import {
|
|
9
9
|
callCreateVerificationCode,
|
|
10
10
|
callRefreshSession,
|
|
@@ -79,9 +79,7 @@ export async function signInImpl(
|
|
|
79
79
|
},
|
|
80
80
|
): Promise<SignInResult> {
|
|
81
81
|
const fx = signInFx(ctx, provider, args, options);
|
|
82
|
-
return Fx.run(
|
|
83
|
-
fx.pipe(Fx.recover((e) => Fx.fatal((e as AuthError).toConvexError()))),
|
|
84
|
-
);
|
|
82
|
+
return Fx.run(fx.pipe(Fx.recover((e) => Fx.fatal(e))));
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
/**
|
|
@@ -104,7 +102,7 @@ function signInFx(
|
|
|
104
102
|
generateTokens: boolean;
|
|
105
103
|
allowExtraProviders: boolean;
|
|
106
104
|
},
|
|
107
|
-
): FxType<SignInResult,
|
|
105
|
+
): FxType<SignInResult, ConvexError<any>> {
|
|
108
106
|
return Fx.gen(function* () {
|
|
109
107
|
// --- Refresh token (no provider) ---
|
|
110
108
|
if (provider === null && args.refreshToken) {
|
|
@@ -133,7 +131,10 @@ function signInFx(
|
|
|
133
131
|
// --- Provider is required past this point ---
|
|
134
132
|
const resolvedProvider = yield* provider != null
|
|
135
133
|
? Fx.succeed(provider)
|
|
136
|
-
:
|
|
134
|
+
: Cv.fail({
|
|
135
|
+
code: "SIGN_IN_MISSING_PARAMS",
|
|
136
|
+
message: "Cannot sign in: missing provider, code, or refresh token.",
|
|
137
|
+
});
|
|
137
138
|
|
|
138
139
|
// --- Dispatch by provider type ---
|
|
139
140
|
return yield* Fx.match(resolvedProvider).on("type", {
|
|
@@ -167,7 +168,7 @@ function handleEmailAndPhoneProviderFx(
|
|
|
167
168
|
): FxType<
|
|
168
169
|
| { kind: "started"; started: true }
|
|
169
170
|
| { kind: "signedIn"; signedIn: SessionInfoWithTokens },
|
|
170
|
-
|
|
171
|
+
ConvexError<any>
|
|
171
172
|
> {
|
|
172
173
|
return Fx.gen(function* () {
|
|
173
174
|
// --- Code verification path ---
|
|
@@ -182,7 +183,10 @@ function handleEmailAndPhoneProviderFx(
|
|
|
182
183
|
);
|
|
183
184
|
const verified = yield* result != null
|
|
184
185
|
? Fx.succeed(result)
|
|
185
|
-
:
|
|
186
|
+
: Cv.fail({
|
|
187
|
+
code: "INVALID_VERIFICATION_CODE",
|
|
188
|
+
message: "Invalid or expired verification code.",
|
|
189
|
+
});
|
|
186
190
|
return {
|
|
187
191
|
kind: "signedIn" as const,
|
|
188
192
|
signedIn: verified as SessionInfoWithTokens,
|
|
@@ -196,10 +200,10 @@ function handleEmailAndPhoneProviderFx(
|
|
|
196
200
|
? yield* Fx.from({
|
|
197
201
|
ok: async () => provider.generateVerificationToken!(),
|
|
198
202
|
err: () =>
|
|
199
|
-
|
|
200
|
-
"INTERNAL_ERROR",
|
|
201
|
-
"Failed to generate verification token",
|
|
202
|
-
),
|
|
203
|
+
Cv.error({
|
|
204
|
+
code: "INTERNAL_ERROR",
|
|
205
|
+
message: "Failed to generate verification token",
|
|
206
|
+
}),
|
|
203
207
|
})
|
|
204
208
|
: generateRandomString(32, alphabet);
|
|
205
209
|
const expirationTime =
|
|
@@ -242,7 +246,10 @@ function handleEmailAndPhoneProviderFx(
|
|
|
242
246
|
ctx,
|
|
243
247
|
),
|
|
244
248
|
err: () =>
|
|
245
|
-
|
|
249
|
+
Cv.error({
|
|
250
|
+
code: "INTERNAL_ERROR",
|
|
251
|
+
message: "Failed to send email code",
|
|
252
|
+
}),
|
|
246
253
|
}),
|
|
247
254
|
phone: (p) =>
|
|
248
255
|
Fx.from({
|
|
@@ -252,7 +259,10 @@ function handleEmailAndPhoneProviderFx(
|
|
|
252
259
|
ctx,
|
|
253
260
|
),
|
|
254
261
|
err: () =>
|
|
255
|
-
|
|
262
|
+
Cv.error({
|
|
263
|
+
code: "INTERNAL_ERROR",
|
|
264
|
+
message: "Failed to send phone code",
|
|
265
|
+
}),
|
|
256
266
|
}),
|
|
257
267
|
});
|
|
258
268
|
return { kind: "started" as const, started: true as const };
|
|
@@ -275,7 +285,7 @@ function handleCredentialsFx(
|
|
|
275
285
|
): FxType<
|
|
276
286
|
| { kind: "signedIn"; signedIn: SessionInfo | null }
|
|
277
287
|
| { kind: "totpRequired"; verifier: string },
|
|
278
|
-
|
|
288
|
+
ConvexError<any>
|
|
279
289
|
> {
|
|
280
290
|
return Fx.gen(function* () {
|
|
281
291
|
const result = yield* Fx.promise(() =>
|
|
@@ -338,7 +348,7 @@ function handleOAuthProviderFx(
|
|
|
338
348
|
): FxType<
|
|
339
349
|
| { kind: "signedIn"; signedIn: SessionInfoWithTokens | null }
|
|
340
350
|
| { kind: "redirect"; redirect: string; verifier: string },
|
|
341
|
-
|
|
351
|
+
ConvexError<any>
|
|
342
352
|
> {
|
|
343
353
|
return Fx.gen(function* () {
|
|
344
354
|
// --- Code verification path ---
|
|
@@ -368,12 +378,10 @@ function handleOAuthProviderFx(
|
|
|
368
378
|
if (args.params?.redirectTo !== undefined) {
|
|
369
379
|
yield* Fx.guard(
|
|
370
380
|
typeof args.params.redirectTo !== "string",
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
),
|
|
376
|
-
),
|
|
381
|
+
Cv.fail({
|
|
382
|
+
code: "INVALID_REDIRECT",
|
|
383
|
+
message: `Expected \`redirectTo\` to be a string, got ${args.params.redirectTo}`,
|
|
384
|
+
}),
|
|
377
385
|
);
|
|
378
386
|
redirect.searchParams.set("redirectTo", args.params.redirectTo);
|
|
379
387
|
}
|
|
@@ -395,26 +403,25 @@ function handleSsoProviderFx(
|
|
|
395
403
|
args: {
|
|
396
404
|
params?: Record<string, any>;
|
|
397
405
|
},
|
|
398
|
-
): FxType<
|
|
406
|
+
): FxType<
|
|
407
|
+
{ kind: "redirect"; redirect: string; verifier: string },
|
|
408
|
+
ConvexError<any>
|
|
409
|
+
> {
|
|
399
410
|
return Fx.gen(function* () {
|
|
400
411
|
const enterpriseId = args.params?.enterpriseId;
|
|
401
412
|
if (!enterpriseId || typeof enterpriseId !== "string") {
|
|
402
|
-
return yield*
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
),
|
|
407
|
-
);
|
|
413
|
+
return yield* Cv.fail({
|
|
414
|
+
code: "SIGN_IN_MISSING_PARAMS",
|
|
415
|
+
message: "enterpriseId is required for SSO sign-in.",
|
|
416
|
+
});
|
|
408
417
|
}
|
|
409
418
|
|
|
410
419
|
const protocol: "oidc" | "saml" = args.params?.protocol ?? "oidc";
|
|
411
420
|
if (protocol !== "oidc" && protocol !== "saml") {
|
|
412
|
-
return yield*
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
),
|
|
417
|
-
);
|
|
421
|
+
return yield* Cv.fail({
|
|
422
|
+
code: "SIGN_IN_MISSING_PARAMS",
|
|
423
|
+
message: `Invalid SSO protocol: ${protocol as string}. Expected "oidc" or "saml".`,
|
|
424
|
+
});
|
|
418
425
|
}
|
|
419
426
|
|
|
420
427
|
const verifier = yield* Fx.promise(() => callVerifier(ctx));
|