@robelest/convex-auth 0.0.4-preview.22 → 0.0.4-preview.24
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 +10 -11
- 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/index.js +2 -2
- package/dist/component/model.d.ts +9 -9
- 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 +41 -41
- package/dist/component/server/auth.d.ts +127 -130
- package/dist/component/server/auth.d.ts.map +1 -1
- package/dist/component/server/auth.js +100 -64
- package/dist/component/server/auth.js.map +1 -1
- package/dist/component/server/context.js +53 -0
- package/dist/component/server/context.js.map +1 -0
- package/dist/component/server/core.js +113 -250
- 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 +59 -16
- 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.d.ts +85 -0
- package/dist/component/server/http.d.ts.map +1 -0
- package/dist/component/server/http.js +85 -22
- 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 +5 -5
- package/dist/component/server/runtime.js +156 -113
- 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 +127 -130
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +100 -64
- package/dist/server/auth.js.map +1 -1
- package/dist/server/context.d.ts +1 -0
- package/dist/server/context.js +53 -0
- package/dist/server/context.js.map +1 -0
- package/dist/server/core.d.ts +74 -195
- package/dist/server/core.d.ts.map +1 -1
- package/dist/server/core.js +113 -250
- 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 +59 -16
- 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 +81 -3
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +84 -21
- 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 +3 -2
- package/dist/server/index.js +2 -2
- package/dist/server/limits.js +21 -30
- package/dist/server/limits.js.map +1 -1
- package/dist/server/mounts.d.ts +25 -63
- package/dist/server/mounts.d.ts.map +1 -1
- package/dist/server/mounts.js +46 -107
- 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 +12 -12
- 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 +14 -12
- 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/signout.js.map +1 -1
- package/dist/server/mutations/store.d.ts +83 -83
- 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 +7 -7
- 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 +11 -11
- package/dist/server/runtime.js +155 -112
- 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 +1 -5
- package/src/authorization/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 +9 -3
- 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 +240 -182
- package/src/server/context.ts +90 -0
- package/src/server/core.ts +195 -286
- 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 +289 -30
- package/src/server/identity.ts +5 -5
- package/src/server/index.ts +9 -3
- package/src/server/limits.ts +53 -80
- package/src/server/mounts.ts +56 -80
- 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 +340 -302
- 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
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
import { Fx } from "@robelest/fx";
|
|
2
|
+
import { Cv } from "@robelest/fx/convex";
|
|
1
3
|
import type { GenericActionCtx, HttpRouter } from "convex/server";
|
|
4
|
+
import { ConvexError } from "convex/values";
|
|
2
5
|
import { serialize as serializeCookie } from "cookie";
|
|
3
6
|
|
|
4
7
|
import { redirectToParamCookie, useRedirectToParam } from "../cookies";
|
|
5
|
-
import { isAuthError } from "../errors";
|
|
6
|
-
import { Fx } from "@robelest/fx";
|
|
7
|
-
|
|
8
|
-
import { AuthError } from "../authError";
|
|
9
8
|
import { addSSORoutes, convertErrorsToResponse, getCookies } from "../http";
|
|
10
9
|
import type { SSORuntimeRoute } from "../http";
|
|
11
10
|
import { createOAuthAuthorizationURL, handleOAuthCallback } from "../oauth";
|
|
@@ -207,12 +206,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
207
206
|
runtimeRoute.protocol !== "saml" ||
|
|
208
207
|
runtimeRoute.rest.length !== 1 ||
|
|
209
208
|
runtimeRoute.rest[0] !== "acs",
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
).toConvexError(),
|
|
215
|
-
),
|
|
209
|
+
Cv.fail({
|
|
210
|
+
code: "INVALID_PARAMETERS",
|
|
211
|
+
message: "Invalid enterprise runtime path.",
|
|
212
|
+
}),
|
|
216
213
|
);
|
|
217
214
|
|
|
218
215
|
const enterpriseId = runtimeRoute.enterpriseId;
|
|
@@ -230,10 +227,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
230
227
|
config: loaded.config,
|
|
231
228
|
}),
|
|
232
229
|
err: (e) =>
|
|
233
|
-
|
|
234
|
-
"OAUTH_PROVIDER_ERROR",
|
|
235
|
-
`SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
236
|
-
)
|
|
230
|
+
Cv.error({
|
|
231
|
+
code: "OAUTH_PROVIDER_ERROR",
|
|
232
|
+
message: `SAML response parse failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
233
|
+
}),
|
|
237
234
|
});
|
|
238
235
|
|
|
239
236
|
yield* Fx.from({
|
|
@@ -247,10 +244,11 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
247
244
|
return Promise.resolve();
|
|
248
245
|
},
|
|
249
246
|
err: () =>
|
|
250
|
-
|
|
251
|
-
"OAUTH_INVALID_STATE",
|
|
252
|
-
|
|
253
|
-
|
|
247
|
+
Cv.error({
|
|
248
|
+
code: "OAUTH_INVALID_STATE",
|
|
249
|
+
message:
|
|
250
|
+
"SAML RelayState did not match the pending login request.",
|
|
251
|
+
}),
|
|
254
252
|
});
|
|
255
253
|
|
|
256
254
|
const { samlAttributes, samlSessionIndex, ...userProfile } =
|
|
@@ -331,10 +329,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
331
329
|
runtimeRoute.rest.length !== 1 ||
|
|
332
330
|
runtimeRoute.rest[0] !== "slo"
|
|
333
331
|
) {
|
|
334
|
-
throw
|
|
335
|
-
"INVALID_PARAMETERS",
|
|
336
|
-
"Invalid enterprise runtime path.",
|
|
337
|
-
)
|
|
332
|
+
throw Cv.error({
|
|
333
|
+
code: "INVALID_PARAMETERS",
|
|
334
|
+
message: "Invalid enterprise runtime path.",
|
|
335
|
+
});
|
|
338
336
|
}
|
|
339
337
|
const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(
|
|
340
338
|
ctx,
|
|
@@ -371,10 +369,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
371
369
|
if (parsedMessage.hasSamlResponse) {
|
|
372
370
|
return new Response(null, { status: 204 });
|
|
373
371
|
}
|
|
374
|
-
throw
|
|
375
|
-
"INVALID_PARAMETERS",
|
|
376
|
-
"Missing SAML logout payload.",
|
|
377
|
-
)
|
|
372
|
+
throw Cv.error({
|
|
373
|
+
code: "INVALID_PARAMETERS",
|
|
374
|
+
message: "Missing SAML logout payload.",
|
|
375
|
+
});
|
|
378
376
|
};
|
|
379
377
|
|
|
380
378
|
const handleScimRequest = async (
|
|
@@ -645,7 +643,7 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
645
643
|
userId,
|
|
646
644
|
data: patchData,
|
|
647
645
|
});
|
|
648
|
-
const resolution = await auth.member.
|
|
646
|
+
const resolution = await auth.member.inspect(state.ctx, {
|
|
649
647
|
groupId: state.enterprise.groupId,
|
|
650
648
|
userId,
|
|
651
649
|
});
|
|
@@ -711,7 +709,7 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
711
709
|
);
|
|
712
710
|
if (missing) return missing;
|
|
713
711
|
const userId = state.parsedPath.resourceId!;
|
|
714
|
-
const resolution = await auth.member.
|
|
712
|
+
const resolution = await auth.member.inspect(state.ctx, {
|
|
715
713
|
groupId: state.enterprise.groupId,
|
|
716
714
|
userId,
|
|
717
715
|
});
|
|
@@ -961,15 +959,12 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
961
959
|
);
|
|
962
960
|
const userId = match?.[1];
|
|
963
961
|
if (userId) {
|
|
964
|
-
const resolution = await auth.member.
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
);
|
|
962
|
+
const resolution = await auth.member.inspect(state.ctx, {
|
|
963
|
+
groupId,
|
|
964
|
+
userId,
|
|
965
|
+
});
|
|
968
966
|
if (resolution.membership) {
|
|
969
|
-
await auth.member.delete(
|
|
970
|
-
state.ctx,
|
|
971
|
-
resolution.membership._id,
|
|
972
|
-
);
|
|
967
|
+
await auth.member.delete(state.ctx, resolution.membership._id);
|
|
973
968
|
}
|
|
974
969
|
}
|
|
975
970
|
}
|
|
@@ -1105,7 +1100,13 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
1105
1100
|
) {
|
|
1106
1101
|
return scimError(400, "invalidFilter", error.message);
|
|
1107
1102
|
}
|
|
1108
|
-
if (
|
|
1103
|
+
if (
|
|
1104
|
+
error instanceof ConvexError &&
|
|
1105
|
+
typeof error.data === "object" &&
|
|
1106
|
+
error.data !== null &&
|
|
1107
|
+
"code" in error.data &&
|
|
1108
|
+
"message" in error.data
|
|
1109
|
+
) {
|
|
1109
1110
|
const code = error.data.code as string;
|
|
1110
1111
|
const status =
|
|
1111
1112
|
code === "MISSING_BEARER_TOKEN" || code === "INVALID_API_KEY"
|
|
@@ -1141,7 +1142,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
1141
1142
|
const url = new URL(request.url);
|
|
1142
1143
|
const verifier = url.searchParams.get("code");
|
|
1143
1144
|
if (!verifier) {
|
|
1144
|
-
throw
|
|
1145
|
+
throw Cv.error({
|
|
1146
|
+
code: "OAUTH_MISSING_VERIFIER",
|
|
1147
|
+
message: "Missing sign-in verifier.",
|
|
1148
|
+
});
|
|
1145
1149
|
}
|
|
1146
1150
|
const { loaded, enterprise } = await loadActiveEnterpriseSamlOrThrow(
|
|
1147
1151
|
ctx,
|
|
@@ -1204,7 +1208,10 @@ export function addEnterpriseHttpRuntime(deps: EnterpriseHttpRuntimeDeps) {
|
|
|
1204
1208
|
const url = new URL(request.url);
|
|
1205
1209
|
const verifier = url.searchParams.get("code");
|
|
1206
1210
|
if (!verifier) {
|
|
1207
|
-
throw
|
|
1211
|
+
throw Cv.error({
|
|
1212
|
+
code: "OAUTH_MISSING_VERIFIER",
|
|
1213
|
+
message: "Missing sign-in verifier.",
|
|
1214
|
+
});
|
|
1208
1215
|
}
|
|
1209
1216
|
const { enterprise, oidc } = await loadEnterpriseOidcOrThrow(
|
|
1210
1217
|
ctx,
|
package/src/server/http.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Fx } from "@robelest/fx";
|
|
2
|
+
import { Cv } from "@robelest/fx/convex";
|
|
1
3
|
import {
|
|
2
4
|
GenericActionCtx,
|
|
3
5
|
GenericDataModel,
|
|
@@ -7,13 +9,262 @@ import {
|
|
|
7
9
|
import { ConvexError } from "convex/values";
|
|
8
10
|
import { parse as parseCookies } from "cookie";
|
|
9
11
|
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
import type {
|
|
13
|
+
AuthContext,
|
|
14
|
+
OptionalAuthContext,
|
|
15
|
+
UserDoc,
|
|
16
|
+
} from "./auth";
|
|
17
|
+
import {
|
|
18
|
+
createUnauthenticatedAuthContext,
|
|
19
|
+
getAuthContextForUser,
|
|
20
|
+
getSessionUserId,
|
|
21
|
+
} from "./context";
|
|
14
22
|
import type { CorsConfig, HttpKeyContext } from "./types";
|
|
15
23
|
import { logError } from "./utils";
|
|
16
24
|
|
|
25
|
+
type HttpContextAuthLike = {
|
|
26
|
+
user: {
|
|
27
|
+
get: (ctx: any, userId: string) => Promise<UserDoc>;
|
|
28
|
+
getActiveGroup: (
|
|
29
|
+
ctx: any,
|
|
30
|
+
args: { userId: string },
|
|
31
|
+
) => Promise<string | null>;
|
|
32
|
+
};
|
|
33
|
+
member: {
|
|
34
|
+
inspect: (
|
|
35
|
+
ctx: any,
|
|
36
|
+
args: { userId: string; groupId: string },
|
|
37
|
+
) => Promise<{
|
|
38
|
+
membership: unknown;
|
|
39
|
+
roleIds: string[];
|
|
40
|
+
grants: string[];
|
|
41
|
+
}>;
|
|
42
|
+
};
|
|
43
|
+
key: {
|
|
44
|
+
verify: (ctx: GenericActionCtx<any>, rawKey: string) => Promise<{
|
|
45
|
+
userId: string;
|
|
46
|
+
keyId: string;
|
|
47
|
+
scopes: HttpKeyContext["key"]["scopes"];
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Auth context returned by `auth.http.context(ctx, request)`.
|
|
54
|
+
*
|
|
55
|
+
* This resolves raw HTTP authentication in two steps:
|
|
56
|
+
* 1. session auth from `ctx.auth.getUserIdentity()`
|
|
57
|
+
* 2. API key auth from `Authorization: Bearer sk_*`
|
|
58
|
+
*
|
|
59
|
+
* The `source` field tells you which authentication path succeeded.
|
|
60
|
+
* When `source === "key"`, the verified API key metadata is available on
|
|
61
|
+
* `key`.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const authContext = await auth.http.context(ctx, request);
|
|
66
|
+
* if (authContext.source === "key") {
|
|
67
|
+
* console.log(authContext.key.keyId);
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export type HttpAuthContext =
|
|
72
|
+
| (AuthContext & {
|
|
73
|
+
/** The request authenticated through a browser or session token. */
|
|
74
|
+
source: "session";
|
|
75
|
+
/** No API key was used for this request. */
|
|
76
|
+
key: null;
|
|
77
|
+
})
|
|
78
|
+
| (AuthContext & {
|
|
79
|
+
/** The request authenticated through an API key. */
|
|
80
|
+
source: "key";
|
|
81
|
+
/** Verified API key metadata for the request. */
|
|
82
|
+
key: HttpKeyContext["key"];
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Nullable HTTP auth context returned by
|
|
87
|
+
* `auth.http.context(ctx, request, { optional: true })`.
|
|
88
|
+
*
|
|
89
|
+
* This preserves a stable auth-shaped object for raw `httpAction` handlers
|
|
90
|
+
* that allow anonymous callers.
|
|
91
|
+
*/
|
|
92
|
+
export type OptionalHttpAuthContext =
|
|
93
|
+
| (OptionalAuthContext & {
|
|
94
|
+
/** No authentication source was resolved. */
|
|
95
|
+
source: null;
|
|
96
|
+
/** No API key metadata is available. */
|
|
97
|
+
key: null;
|
|
98
|
+
})
|
|
99
|
+
| HttpAuthContext;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Configuration for {@link createAuth().http.context}.
|
|
103
|
+
*
|
|
104
|
+
* This mirrors {@link AuthContextConfig} for raw HTTP handlers and adds support
|
|
105
|
+
* for enriching mixed session/API-key auth results.
|
|
106
|
+
*
|
|
107
|
+
* @typeParam TResolve - Extra fields returned from `resolve()` and merged into
|
|
108
|
+
* the resolved HTTP auth context.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* const authContext = await auth.http.context(ctx, request, {
|
|
113
|
+
* resolve: async (_ctx, user, authState) => ({
|
|
114
|
+
* email: user.email,
|
|
115
|
+
* isMachineRequest: authState.source === "key",
|
|
116
|
+
* }),
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export type HttpAuthContextConfig<
|
|
121
|
+
TResolve extends Record<string, unknown> = Record<string, never>,
|
|
122
|
+
> = {
|
|
123
|
+
/**
|
|
124
|
+
* Allow unauthenticated callers and return a null-shaped auth object instead
|
|
125
|
+
* of throwing `NOT_SIGNED_IN`.
|
|
126
|
+
*/
|
|
127
|
+
optional?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Attach additional derived fields to the resolved HTTP auth context.
|
|
130
|
+
*
|
|
131
|
+
* This callback runs only when authentication succeeds.
|
|
132
|
+
*/
|
|
133
|
+
resolve?: (
|
|
134
|
+
ctx: GenericActionCtx<any>,
|
|
135
|
+
user: UserDoc,
|
|
136
|
+
auth: HttpAuthContext,
|
|
137
|
+
) => Promise<TResolve> | TResolve;
|
|
138
|
+
/**
|
|
139
|
+
* Override or wrap HTTP auth resolution.
|
|
140
|
+
*
|
|
141
|
+
* Return `undefined` to use the built-in session-or-key resolver, `null` for
|
|
142
|
+
* an explicit unauthenticated state, or a fully resolved
|
|
143
|
+
* {@link HttpAuthContext}.
|
|
144
|
+
*/
|
|
145
|
+
authResolve?: (
|
|
146
|
+
ctx: GenericActionCtx<any>,
|
|
147
|
+
fallback: () => Promise<HttpAuthContext | null>,
|
|
148
|
+
) =>
|
|
149
|
+
| Promise<HttpAuthContext | null | undefined>
|
|
150
|
+
| HttpAuthContext
|
|
151
|
+
| null
|
|
152
|
+
| undefined;
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
function createNotSignedInError() {
|
|
156
|
+
return Cv.error({
|
|
157
|
+
code: "NOT_SIGNED_IN",
|
|
158
|
+
message: "Authentication required.",
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function getHttpKeyContext(
|
|
163
|
+
auth: HttpContextAuthLike,
|
|
164
|
+
ctx: GenericActionCtx<any>,
|
|
165
|
+
request: Request,
|
|
166
|
+
): Promise<HttpAuthContext | null> {
|
|
167
|
+
const authHeader = request.headers.get("Authorization");
|
|
168
|
+
if (!authHeader?.startsWith("Bearer sk_")) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
const verified = await auth.key.verify(ctx, authHeader.slice(7));
|
|
174
|
+
const authContext = await getAuthContextForUser(auth, ctx, verified.userId);
|
|
175
|
+
return {
|
|
176
|
+
...authContext,
|
|
177
|
+
source: "key",
|
|
178
|
+
key: {
|
|
179
|
+
userId: verified.userId,
|
|
180
|
+
keyId: verified.keyId,
|
|
181
|
+
scopes: verified.scopes,
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
} catch {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function resolveHttpAuthContext(
|
|
190
|
+
auth: HttpContextAuthLike,
|
|
191
|
+
ctx: GenericActionCtx<any>,
|
|
192
|
+
request: Request,
|
|
193
|
+
): Promise<HttpAuthContext | null> {
|
|
194
|
+
const sessionUserId = await getSessionUserId(ctx);
|
|
195
|
+
if (sessionUserId !== null) {
|
|
196
|
+
const authContext = await getAuthContextForUser(auth, ctx, sessionUserId);
|
|
197
|
+
return {
|
|
198
|
+
...authContext,
|
|
199
|
+
source: "session",
|
|
200
|
+
key: null,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return await getHttpKeyContext(auth, ctx, request);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* @internal
|
|
209
|
+
* Create the implementation behind `auth.http.context(...)`.
|
|
210
|
+
*/
|
|
211
|
+
export function createHttpContext(auth: HttpContextAuthLike): {
|
|
212
|
+
<TResolve extends Record<string, unknown> = Record<string, never>>(
|
|
213
|
+
ctx: GenericActionCtx<any>,
|
|
214
|
+
request: Request,
|
|
215
|
+
config: HttpAuthContextConfig<TResolve> & { optional: true },
|
|
216
|
+
): Promise<OptionalHttpAuthContext & TResolve>;
|
|
217
|
+
<TResolve extends Record<string, unknown> = Record<string, never>>(
|
|
218
|
+
ctx: GenericActionCtx<any>,
|
|
219
|
+
request: Request,
|
|
220
|
+
config?: HttpAuthContextConfig<TResolve>,
|
|
221
|
+
): Promise<HttpAuthContext & TResolve>;
|
|
222
|
+
} {
|
|
223
|
+
return (async (
|
|
224
|
+
ctx: GenericActionCtx<any>,
|
|
225
|
+
request: Request,
|
|
226
|
+
config?: HttpAuthContextConfig<any>,
|
|
227
|
+
) => {
|
|
228
|
+
const fallback = () => resolveHttpAuthContext(auth, ctx, request);
|
|
229
|
+
const authOverride = config?.authResolve
|
|
230
|
+
? await config.authResolve(ctx, fallback)
|
|
231
|
+
: undefined;
|
|
232
|
+
const resolved =
|
|
233
|
+
authOverride === undefined ? await fallback() : authOverride;
|
|
234
|
+
|
|
235
|
+
if (resolved === null) {
|
|
236
|
+
if (config?.optional !== true) {
|
|
237
|
+
throw createNotSignedInError();
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
...createUnauthenticatedAuthContext(),
|
|
241
|
+
source: null,
|
|
242
|
+
key: null,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const extra = config?.resolve
|
|
247
|
+
? await config.resolve(ctx, resolved.user, resolved)
|
|
248
|
+
: {};
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
...resolved,
|
|
252
|
+
...extra,
|
|
253
|
+
};
|
|
254
|
+
}) as {
|
|
255
|
+
<TResolve extends Record<string, unknown> = Record<string, never>>(
|
|
256
|
+
ctx: GenericActionCtx<any>,
|
|
257
|
+
request: Request,
|
|
258
|
+
config: HttpAuthContextConfig<TResolve> & { optional: true },
|
|
259
|
+
): Promise<OptionalHttpAuthContext & TResolve>;
|
|
260
|
+
<TResolve extends Record<string, unknown> = Record<string, never>>(
|
|
261
|
+
ctx: GenericActionCtx<any>,
|
|
262
|
+
request: Request,
|
|
263
|
+
config?: HttpAuthContextConfig<TResolve>,
|
|
264
|
+
): Promise<HttpAuthContext & TResolve>;
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
|
|
17
268
|
export function createHttpAction(auth: {
|
|
18
269
|
key: { verify: (ctx: GenericActionCtx<any>, rawKey: string) => Promise<any> };
|
|
19
270
|
}) {
|
|
@@ -59,19 +310,21 @@ export function createHttpAction(auth: {
|
|
|
59
310
|
const rawKey = authHeader.slice(7);
|
|
60
311
|
|
|
61
312
|
const keyResult = await Fx.run(
|
|
62
|
-
Fx.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
Fx.fold({
|
|
67
|
-
ok: (result) => ({ ok: true, value: result }) as const,
|
|
68
|
-
err: (error) => ({ ok: false, error }) as const,
|
|
69
|
-
}),
|
|
313
|
+
Fx.attempt(
|
|
314
|
+
() => auth.key.verify(genericCtx, rawKey),
|
|
315
|
+
(result) => ({ ok: true, value: result }) as const,
|
|
316
|
+
(error) => ({ ok: false, error }) as const,
|
|
70
317
|
),
|
|
71
318
|
);
|
|
72
319
|
|
|
73
320
|
if (!keyResult.ok) {
|
|
74
|
-
if (
|
|
321
|
+
if (
|
|
322
|
+
keyResult.error instanceof ConvexError &&
|
|
323
|
+
typeof keyResult.error.data === "object" &&
|
|
324
|
+
keyResult.error.data !== null &&
|
|
325
|
+
"code" in keyResult.error.data &&
|
|
326
|
+
"message" in keyResult.error.data
|
|
327
|
+
) {
|
|
75
328
|
const { code, message } = keyResult.error.data as {
|
|
76
329
|
code: string;
|
|
77
330
|
message: string;
|
|
@@ -219,7 +472,13 @@ export function convertErrorsToResponse(
|
|
|
219
472
|
err: (error) => error,
|
|
220
473
|
}).pipe(
|
|
221
474
|
Fx.recover((error) => {
|
|
222
|
-
if (
|
|
475
|
+
if (
|
|
476
|
+
error instanceof ConvexError &&
|
|
477
|
+
typeof error.data === "object" &&
|
|
478
|
+
error.data !== null &&
|
|
479
|
+
"code" in error.data &&
|
|
480
|
+
"message" in error.data
|
|
481
|
+
) {
|
|
223
482
|
return Fx.succeed(
|
|
224
483
|
new Response(
|
|
225
484
|
JSON.stringify({
|
|
@@ -426,10 +685,10 @@ export function addSSORoutes(
|
|
|
426
685
|
deps.routeBase,
|
|
427
686
|
);
|
|
428
687
|
if (!route) {
|
|
429
|
-
throw
|
|
430
|
-
"INVALID_PARAMETERS",
|
|
431
|
-
"Invalid enterprise runtime path.",
|
|
432
|
-
)
|
|
688
|
+
throw Cv.error({
|
|
689
|
+
code: "INVALID_PARAMETERS",
|
|
690
|
+
message: "Invalid enterprise runtime path.",
|
|
691
|
+
});
|
|
433
692
|
}
|
|
434
693
|
if (route.protocol === "saml" && route.rest.length === 1) {
|
|
435
694
|
if (route.rest[0] === "metadata") {
|
|
@@ -456,10 +715,10 @@ export function addSSORoutes(
|
|
|
456
715
|
if (route.protocol === "scim" && route.rest[0] === "v2") {
|
|
457
716
|
return await deps.handleScimRequest(ctx, request);
|
|
458
717
|
}
|
|
459
|
-
throw
|
|
460
|
-
"INVALID_PARAMETERS",
|
|
461
|
-
"Invalid enterprise runtime path.",
|
|
462
|
-
)
|
|
718
|
+
throw Cv.error({
|
|
719
|
+
code: "INVALID_PARAMETERS",
|
|
720
|
+
message: "Invalid enterprise runtime path.",
|
|
721
|
+
});
|
|
463
722
|
}),
|
|
464
723
|
),
|
|
465
724
|
});
|
|
@@ -484,10 +743,10 @@ export function addSSORoutes(
|
|
|
484
743
|
if (route?.protocol === "scim" && route.rest[0] === "v2") {
|
|
485
744
|
return await deps.handleScimRequest(ctx, request);
|
|
486
745
|
}
|
|
487
|
-
throw
|
|
488
|
-
"INVALID_PARAMETERS",
|
|
489
|
-
"Invalid enterprise runtime path.",
|
|
490
|
-
)
|
|
746
|
+
throw Cv.error({
|
|
747
|
+
code: "INVALID_PARAMETERS",
|
|
748
|
+
message: "Invalid enterprise runtime path.",
|
|
749
|
+
});
|
|
491
750
|
}),
|
|
492
751
|
),
|
|
493
752
|
});
|
|
@@ -504,10 +763,10 @@ export function addSSORoutes(
|
|
|
504
763
|
if (route?.protocol === "scim" && route.rest[0] === "v2") {
|
|
505
764
|
return await deps.handleScimRequest(ctx, request);
|
|
506
765
|
}
|
|
507
|
-
throw
|
|
508
|
-
"INVALID_PARAMETERS",
|
|
509
|
-
"Invalid enterprise runtime path.",
|
|
510
|
-
)
|
|
766
|
+
throw Cv.error({
|
|
767
|
+
code: "INVALID_PARAMETERS",
|
|
768
|
+
message: "Invalid enterprise runtime path.",
|
|
769
|
+
});
|
|
511
770
|
}),
|
|
512
771
|
),
|
|
513
772
|
});
|
package/src/server/identity.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Cv } from "@robelest/fx/convex";
|
|
2
2
|
|
|
3
3
|
/** @internal */
|
|
4
4
|
export function userIdFromIdentitySubject(subject: string): string {
|
|
@@ -9,10 +9,10 @@ export function userIdFromIdentitySubject(subject: string): string {
|
|
|
9
9
|
rest.length === 0 ||
|
|
10
10
|
rest.some((segment) => segment.length === 0)
|
|
11
11
|
) {
|
|
12
|
-
throw
|
|
13
|
-
"INTERNAL_ERROR",
|
|
14
|
-
"Authenticated identity subject is malformed.",
|
|
15
|
-
);
|
|
12
|
+
throw Cv.error({
|
|
13
|
+
code: "INTERNAL_ERROR",
|
|
14
|
+
message: "Authenticated identity subject is malformed.",
|
|
15
|
+
});
|
|
16
16
|
}
|
|
17
17
|
return userId;
|
|
18
18
|
}
|
package/src/server/index.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { createAuth } from "./auth";
|
|
2
2
|
export type {
|
|
3
3
|
AuthApi,
|
|
4
4
|
AuthApiBase,
|
|
5
|
+
AuthContext,
|
|
6
|
+
AuthContextConfig,
|
|
5
7
|
AuthConfig,
|
|
6
|
-
AuthCtxConfig,
|
|
7
|
-
AuthResolvedContext,
|
|
8
8
|
ConvexAuthResult,
|
|
9
9
|
InferAuth,
|
|
10
10
|
InferClientApi,
|
|
11
|
+
OptionalAuthContext,
|
|
11
12
|
UserDoc,
|
|
12
13
|
} from "./auth";
|
|
14
|
+
export type {
|
|
15
|
+
HttpAuthContext,
|
|
16
|
+
HttpAuthContextConfig,
|
|
17
|
+
OptionalHttpAuthContext,
|
|
18
|
+
} from "./http";
|
|
13
19
|
export type {
|
|
14
20
|
EnterpriseAdminAuthorizationInput,
|
|
15
21
|
EnterpriseAdminPermission,
|