@robelest/convex-auth 0.0.4-preview.25 → 0.0.4-preview.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -36
- package/dist/bin.js +5765 -4880
- package/dist/browser/index.d.ts +30 -0
- package/dist/browser/index.js +93 -0
- package/dist/browser/locks.js +11 -0
- package/dist/browser/navigation.js +14 -0
- package/dist/{factors → browser}/passkey.js +23 -32
- package/dist/browser/runtime.js +92 -0
- package/dist/client/core/types.d.ts +452 -5
- package/dist/client/core/types.js +17 -0
- package/dist/client/errors.js +19 -0
- package/dist/client/factors/device.js +94 -0
- package/dist/{factors → client/factors}/totp.js +12 -4
- package/dist/client/index.d.ts +47 -1
- package/dist/client/index.js +269 -232
- package/dist/client/runtime/mutex.js +24 -0
- package/dist/client/runtime/proxy.js +30 -0
- package/dist/client/runtime/storage.js +45 -0
- package/dist/client/services/adapters.js +7 -0
- package/dist/client/services/http.js +6 -0
- package/dist/client/services/resolve.js +13 -0
- package/dist/client/services/runtime.js +6 -0
- package/dist/component/_generated/component.d.ts +1355 -1399
- package/dist/component/convex.config.d.ts +2 -2
- package/dist/component/index.d.ts +4 -26
- package/dist/component/index.js +1 -1
- package/dist/component/model.d.ts +26 -112
- package/dist/component/model.js +76 -54
- package/dist/component/modules.js +38 -0
- package/dist/component/public/factors/devices.js +1 -1
- package/dist/component/public/factors/passkeys.js +1 -1
- package/dist/component/public/factors/totp.js +1 -1
- package/dist/component/public/groups/core.js +2 -2
- package/dist/component/public/groups/invites.js +1 -1
- package/dist/component/public/groups/members.js +1 -1
- package/dist/component/public/identity/accounts.js +1 -1
- package/dist/component/public/identity/codes.js +1 -1
- package/dist/component/public/identity/sessions.js +39 -2
- package/dist/component/public/identity/tokens.js +82 -4
- package/dist/component/public/identity/users.js +1 -1
- package/dist/component/public/identity/verifiers.js +10 -4
- package/dist/component/public/security/keys.js +1 -1
- package/dist/component/public/security/limits.js +1 -1
- package/dist/component/public/{enterprise → sso}/audit.js +26 -26
- package/dist/component/public/sso/core.js +263 -0
- package/dist/component/public/sso/domains.js +280 -0
- package/dist/component/public/{enterprise → sso}/scim.js +87 -87
- package/dist/component/public/sso/secrets.js +125 -0
- package/dist/component/public/{enterprise → sso}/webhooks.js +59 -59
- package/dist/component/public.js +9 -9
- package/dist/component/schema.d.ts +472 -393
- package/dist/component/schema.js +36 -35
- package/dist/core/index.d.ts +380 -0
- package/dist/core/index.js +83 -0
- package/dist/otel.d.ts +69 -0
- package/dist/otel.js +82 -0
- package/dist/providers/anonymous.d.ts +15 -34
- package/dist/providers/anonymous.js +27 -35
- package/dist/providers/apple.d.ts +59 -0
- package/dist/providers/apple.js +58 -0
- package/dist/providers/credentials.d.ts +18 -34
- package/dist/providers/credentials.js +16 -27
- package/dist/providers/custom.d.ts +94 -0
- package/dist/providers/custom.js +119 -0
- package/dist/providers/device.d.ts +15 -49
- package/dist/providers/device.js +17 -34
- package/dist/providers/email.d.ts +21 -38
- package/dist/providers/email.js +36 -55
- package/dist/providers/github.d.ts +54 -0
- package/dist/providers/github.js +75 -0
- package/dist/providers/google.d.ts +54 -0
- package/dist/providers/google.js +61 -0
- package/dist/providers/index.d.ts +16 -12
- package/dist/providers/index.js +15 -11
- package/dist/providers/microsoft.d.ts +57 -0
- package/dist/providers/microsoft.js +101 -0
- package/dist/providers/passkey.d.ts +19 -35
- package/dist/providers/passkey.js +20 -30
- package/dist/providers/password.d.ts +17 -18
- package/dist/providers/password.js +121 -143
- package/dist/providers/phone.d.ts +13 -28
- package/dist/providers/phone.js +21 -46
- package/dist/providers/sso.d.ts +16 -36
- package/dist/providers/sso.js +21 -22
- package/dist/providers/totp.d.ts +13 -29
- package/dist/providers/totp.js +17 -27
- package/dist/server/auth-context.d.ts +204 -0
- package/dist/server/auth-context.js +76 -0
- package/dist/server/auth.d.ts +99 -244
- package/dist/server/auth.js +56 -152
- package/dist/server/componentContext.d.ts +12 -0
- package/dist/server/componentContext.js +1 -0
- package/dist/server/config.js +6 -67
- package/dist/server/constants.js +6 -0
- package/dist/server/contract.d.ts +105 -0
- package/dist/server/contract.js +43 -0
- package/dist/server/cookies.js +3 -2
- package/dist/server/core.js +31 -36
- package/dist/server/crypto.js +34 -44
- package/dist/server/db.js +6 -1
- package/dist/server/device.js +96 -130
- package/dist/server/env.js +48 -0
- package/dist/server/errors.js +20 -0
- package/dist/server/http.d.ts +15 -59
- package/dist/server/http.js +136 -120
- package/dist/server/identity.js +2 -2
- package/dist/server/index.d.ts +5 -4
- package/dist/server/index.js +3 -3
- package/dist/server/keys.js +10 -1
- package/dist/server/limits.js +26 -26
- package/dist/server/log.js +28 -0
- package/dist/server/mounts.d.ts +1107 -296
- package/dist/server/mounts.js +315 -196
- package/dist/server/mutations/account.js +11 -14
- package/dist/server/mutations/code.js +6 -5
- package/dist/server/mutations/invalidate.js +9 -11
- package/dist/server/mutations/oauth.js +112 -73
- package/dist/server/mutations/refresh.js +47 -97
- package/dist/server/mutations/register.js +37 -35
- package/dist/server/mutations/retrieve.js +16 -16
- package/dist/server/mutations/signature.js +15 -18
- package/dist/server/mutations/signin.js +10 -5
- package/dist/server/mutations/signout.js +11 -14
- package/dist/server/mutations/store.js +25 -18
- package/dist/server/mutations/verifier.js +11 -8
- package/dist/server/mutations/verify.js +53 -41
- package/dist/server/oauth/factory.js +44 -0
- package/dist/server/oauth/index.js +12 -0
- package/dist/server/oauth/runtime.js +248 -0
- package/dist/server/passkey.js +331 -365
- package/dist/server/payloads.d.ts +16 -0
- package/dist/server/payloads.js +30 -0
- package/dist/server/{ssr.d.ts → prefetch.d.ts} +2 -2
- package/dist/server/prefetch.js +635 -0
- package/dist/server/random.js +19 -0
- package/dist/server/redirects.js +10 -5
- package/dist/server/refresh.js +14 -86
- package/dist/server/runtime.d.ts +531 -31
- package/dist/server/runtime.js +106 -267
- package/dist/server/secret.js +44 -0
- package/dist/server/services/config.js +10 -0
- package/dist/server/services/group.js +211 -0
- package/dist/server/services/logger.js +8 -0
- package/dist/server/services/providers.js +22 -0
- package/dist/server/services/refresh.js +8 -0
- package/dist/server/services/resolve.js +27 -0
- package/dist/server/services/signin.js +8 -0
- package/dist/server/sessions.js +35 -34
- package/dist/server/signin.js +229 -140
- package/dist/server/{enterprise → sso}/config.js +10 -3
- package/dist/server/sso/domain.d.ts +614 -0
- package/dist/server/sso/domain.js +1175 -0
- package/dist/server/sso/http.js +1060 -0
- package/dist/server/sso/oidc.js +324 -0
- package/dist/server/sso/policies.js +59 -0
- package/dist/server/sso/policy.js +139 -0
- package/dist/server/sso/profile.js +22 -0
- package/dist/server/sso/provision.js +179 -0
- package/dist/{component/server/enterprise → server/sso}/saml.js +142 -56
- package/dist/{component/server/enterprise → server/sso}/scim.js +13 -7
- package/dist/server/sso/shared.js +74 -0
- package/dist/server/sso/validators.js +88 -0
- package/dist/server/sso/webhook.js +94 -0
- package/dist/server/tokens.js +16 -4
- package/dist/server/totp.js +155 -164
- package/dist/server/types.d.ts +306 -296
- package/dist/server/types.js +1 -30
- package/dist/server/url.js +32 -0
- package/dist/server/users.js +74 -40
- package/dist/server/utils/cache.js +51 -0
- package/dist/server/utils/dispatch.js +36 -0
- package/dist/server/utils/retry.js +24 -0
- package/dist/server/utils/span.js +32 -0
- package/dist/shared/errors.js +19 -0
- package/dist/shared/log.js +45 -0
- package/{src/test.ts → dist/test.d.ts} +21 -22
- package/dist/test.js +51 -0
- package/package.json +70 -42
- package/dist/authorization/index.d.ts.map +0 -1
- package/dist/authorization/index.js.map +0 -1
- package/dist/client/core/types.d.ts.map +0 -1
- package/dist/client/index.d.ts.map +0 -1
- package/dist/client/index.js.map +0 -1
- package/dist/component/_generated/api.d.ts +0 -75
- package/dist/component/_generated/api.d.ts.map +0 -1
- package/dist/component/_generated/api.js.map +0 -1
- package/dist/component/_generated/component.d.ts.map +0 -1
- package/dist/component/_generated/dataModel.d.ts +0 -42
- package/dist/component/_generated/dataModel.d.ts.map +0 -1
- package/dist/component/_generated/server.d.ts +0 -117
- package/dist/component/_generated/server.d.ts.map +0 -1
- package/dist/component/_generated/server.js.map +0 -1
- package/dist/component/_virtual/rolldown_runtime.js +0 -18
- package/dist/component/client/core/types.d.ts +0 -2
- package/dist/component/client/index.d.ts +0 -1
- package/dist/component/convex.config.d.ts.map +0 -1
- package/dist/component/convex.config.js.map +0 -1
- package/dist/component/functions.d.ts +0 -25
- package/dist/component/functions.d.ts.map +0 -1
- package/dist/component/functions.js.map +0 -1
- package/dist/component/index.d.ts.map +0 -1
- package/dist/component/model.d.ts.map +0 -1
- package/dist/component/model.js.map +0 -1
- package/dist/component/providers/anonymous.d.ts +0 -54
- package/dist/component/providers/anonymous.d.ts.map +0 -1
- package/dist/component/providers/credentials.d.ts +0 -38
- package/dist/component/providers/credentials.d.ts.map +0 -1
- package/dist/component/providers/device.d.ts +0 -67
- package/dist/component/providers/device.d.ts.map +0 -1
- package/dist/component/providers/email.d.ts +0 -62
- package/dist/component/providers/email.d.ts.map +0 -1
- package/dist/component/providers/oauth.d.ts +0 -25
- package/dist/component/providers/oauth.d.ts.map +0 -1
- package/dist/component/providers/oauth.js +0 -13
- package/dist/component/providers/oauth.js.map +0 -1
- package/dist/component/providers/passkey.d.ts +0 -57
- package/dist/component/providers/passkey.d.ts.map +0 -1
- package/dist/component/providers/password.d.ts +0 -88
- package/dist/component/providers/password.d.ts.map +0 -1
- package/dist/component/providers/phone.d.ts +0 -48
- package/dist/component/providers/phone.d.ts.map +0 -1
- package/dist/component/providers/sso.d.ts +0 -50
- package/dist/component/providers/sso.d.ts.map +0 -1
- package/dist/component/providers/totp.d.ts +0 -45
- package/dist/component/providers/totp.d.ts.map +0 -1
- package/dist/component/public/enterprise/audit.d.ts +0 -73
- package/dist/component/public/enterprise/audit.d.ts.map +0 -1
- package/dist/component/public/enterprise/audit.js.map +0 -1
- package/dist/component/public/enterprise/core.d.ts +0 -176
- package/dist/component/public/enterprise/core.d.ts.map +0 -1
- package/dist/component/public/enterprise/core.js +0 -292
- package/dist/component/public/enterprise/core.js.map +0 -1
- package/dist/component/public/enterprise/domains.d.ts +0 -174
- package/dist/component/public/enterprise/domains.d.ts.map +0 -1
- package/dist/component/public/enterprise/domains.js +0 -271
- package/dist/component/public/enterprise/domains.js.map +0 -1
- package/dist/component/public/enterprise/scim.d.ts +0 -245
- package/dist/component/public/enterprise/scim.d.ts.map +0 -1
- package/dist/component/public/enterprise/scim.js.map +0 -1
- package/dist/component/public/enterprise/secrets.d.ts +0 -78
- package/dist/component/public/enterprise/secrets.d.ts.map +0 -1
- package/dist/component/public/enterprise/secrets.js +0 -118
- package/dist/component/public/enterprise/secrets.js.map +0 -1
- package/dist/component/public/enterprise/webhooks.d.ts +0 -211
- package/dist/component/public/enterprise/webhooks.d.ts.map +0 -1
- package/dist/component/public/enterprise/webhooks.js.map +0 -1
- package/dist/component/public/factors/devices.d.ts +0 -157
- package/dist/component/public/factors/devices.d.ts.map +0 -1
- package/dist/component/public/factors/devices.js.map +0 -1
- package/dist/component/public/factors/passkeys.d.ts +0 -175
- package/dist/component/public/factors/passkeys.d.ts.map +0 -1
- package/dist/component/public/factors/passkeys.js.map +0 -1
- package/dist/component/public/factors/totp.d.ts +0 -189
- package/dist/component/public/factors/totp.d.ts.map +0 -1
- package/dist/component/public/factors/totp.js.map +0 -1
- package/dist/component/public/groups/core.d.ts +0 -137
- package/dist/component/public/groups/core.d.ts.map +0 -1
- package/dist/component/public/groups/core.js.map +0 -1
- package/dist/component/public/groups/invites.d.ts +0 -217
- package/dist/component/public/groups/invites.d.ts.map +0 -1
- package/dist/component/public/groups/invites.js.map +0 -1
- package/dist/component/public/groups/members.d.ts +0 -204
- package/dist/component/public/groups/members.d.ts.map +0 -1
- package/dist/component/public/groups/members.js.map +0 -1
- package/dist/component/public/identity/accounts.d.ts +0 -147
- package/dist/component/public/identity/accounts.d.ts.map +0 -1
- package/dist/component/public/identity/accounts.js.map +0 -1
- package/dist/component/public/identity/codes.d.ts +0 -104
- package/dist/component/public/identity/codes.d.ts.map +0 -1
- package/dist/component/public/identity/codes.js.map +0 -1
- package/dist/component/public/identity/sessions.d.ts +0 -128
- package/dist/component/public/identity/sessions.d.ts.map +0 -1
- package/dist/component/public/identity/sessions.js.map +0 -1
- package/dist/component/public/identity/tokens.d.ts +0 -169
- package/dist/component/public/identity/tokens.d.ts.map +0 -1
- package/dist/component/public/identity/tokens.js.map +0 -1
- package/dist/component/public/identity/users.d.ts +0 -212
- package/dist/component/public/identity/users.d.ts.map +0 -1
- package/dist/component/public/identity/users.js.map +0 -1
- package/dist/component/public/identity/verifiers.d.ts +0 -116
- package/dist/component/public/identity/verifiers.d.ts.map +0 -1
- package/dist/component/public/identity/verifiers.js.map +0 -1
- package/dist/component/public/security/keys.d.ts +0 -209
- package/dist/component/public/security/keys.d.ts.map +0 -1
- package/dist/component/public/security/keys.js.map +0 -1
- package/dist/component/public/security/limits.d.ts +0 -114
- package/dist/component/public/security/limits.d.ts.map +0 -1
- package/dist/component/public/security/limits.js.map +0 -1
- package/dist/component/public.d.ts +0 -28
- package/dist/component/public.d.ts.map +0 -1
- package/dist/component/schema.d.ts.map +0 -1
- package/dist/component/schema.js.map +0 -1
- package/dist/component/server/auth.d.ts +0 -447
- package/dist/component/server/auth.d.ts.map +0 -1
- package/dist/component/server/auth.js +0 -254
- package/dist/component/server/auth.js.map +0 -1
- package/dist/component/server/config.js +0 -121
- package/dist/component/server/config.js.map +0 -1
- package/dist/component/server/context.js +0 -53
- package/dist/component/server/context.js.map +0 -1
- package/dist/component/server/cookies.js +0 -47
- package/dist/component/server/cookies.js.map +0 -1
- package/dist/component/server/core.js +0 -576
- package/dist/component/server/core.js.map +0 -1
- package/dist/component/server/crypto.js +0 -56
- package/dist/component/server/crypto.js.map +0 -1
- package/dist/component/server/db.js +0 -87
- package/dist/component/server/db.js.map +0 -1
- package/dist/component/server/device.js +0 -152
- package/dist/component/server/device.js.map +0 -1
- package/dist/component/server/enterprise/config.js +0 -46
- package/dist/component/server/enterprise/config.js.map +0 -1
- package/dist/component/server/enterprise/domain.js +0 -974
- package/dist/component/server/enterprise/domain.js.map +0 -1
- package/dist/component/server/enterprise/http.js +0 -787
- package/dist/component/server/enterprise/http.js.map +0 -1
- package/dist/component/server/enterprise/oidc.js +0 -248
- package/dist/component/server/enterprise/oidc.js.map +0 -1
- package/dist/component/server/enterprise/policy.js +0 -85
- package/dist/component/server/enterprise/policy.js.map +0 -1
- package/dist/component/server/enterprise/saml.js.map +0 -1
- package/dist/component/server/enterprise/scim.js.map +0 -1
- package/dist/component/server/enterprise/shared.js +0 -51
- package/dist/component/server/enterprise/shared.js.map +0 -1
- package/dist/component/server/http.d.ts +0 -85
- package/dist/component/server/http.d.ts.map +0 -1
- package/dist/component/server/http.js +0 -351
- package/dist/component/server/http.js.map +0 -1
- package/dist/component/server/identity.js +0 -16
- package/dist/component/server/identity.js.map +0 -1
- package/dist/component/server/keys.js +0 -96
- package/dist/component/server/keys.js.map +0 -1
- package/dist/component/server/limits.js +0 -52
- package/dist/component/server/limits.js.map +0 -1
- package/dist/component/server/mutations/account.js +0 -46
- package/dist/component/server/mutations/account.js.map +0 -1
- package/dist/component/server/mutations/code.js +0 -68
- package/dist/component/server/mutations/code.js.map +0 -1
- package/dist/component/server/mutations/invalidate.js +0 -32
- package/dist/component/server/mutations/invalidate.js.map +0 -1
- package/dist/component/server/mutations/oauth.js +0 -116
- package/dist/component/server/mutations/oauth.js.map +0 -1
- package/dist/component/server/mutations/refresh.js +0 -119
- package/dist/component/server/mutations/refresh.js.map +0 -1
- package/dist/component/server/mutations/register.js +0 -87
- package/dist/component/server/mutations/register.js.map +0 -1
- package/dist/component/server/mutations/retrieve.js +0 -61
- package/dist/component/server/mutations/retrieve.js.map +0 -1
- package/dist/component/server/mutations/signature.js +0 -38
- package/dist/component/server/mutations/signature.js.map +0 -1
- package/dist/component/server/mutations/signin.js +0 -27
- package/dist/component/server/mutations/signin.js.map +0 -1
- package/dist/component/server/mutations/signout.js +0 -27
- package/dist/component/server/mutations/signout.js.map +0 -1
- package/dist/component/server/mutations/store/refs.js +0 -15
- package/dist/component/server/mutations/store/refs.js.map +0 -1
- package/dist/component/server/mutations/store.js +0 -70
- package/dist/component/server/mutations/store.js.map +0 -1
- package/dist/component/server/mutations/verifier.js +0 -18
- package/dist/component/server/mutations/verifier.js.map +0 -1
- package/dist/component/server/mutations/verify.js +0 -98
- package/dist/component/server/mutations/verify.js.map +0 -1
- package/dist/component/server/oauth.js +0 -242
- package/dist/component/server/oauth.js.map +0 -1
- package/dist/component/server/passkey.js +0 -415
- package/dist/component/server/passkey.js.map +0 -1
- package/dist/component/server/redirects.js +0 -40
- package/dist/component/server/redirects.js.map +0 -1
- package/dist/component/server/refresh.js +0 -99
- package/dist/component/server/refresh.js.map +0 -1
- package/dist/component/server/runtime.d.ts +0 -136
- package/dist/component/server/runtime.d.ts.map +0 -1
- package/dist/component/server/runtime.js +0 -456
- package/dist/component/server/runtime.js.map +0 -1
- package/dist/component/server/sessions.js +0 -71
- package/dist/component/server/sessions.js.map +0 -1
- package/dist/component/server/signin.js +0 -225
- package/dist/component/server/signin.js.map +0 -1
- package/dist/component/server/tokens.js +0 -17
- package/dist/component/server/tokens.js.map +0 -1
- package/dist/component/server/totp.js +0 -208
- package/dist/component/server/totp.js.map +0 -1
- package/dist/component/server/types.d.ts +0 -949
- package/dist/component/server/types.d.ts.map +0 -1
- package/dist/component/server/types.js +0 -79
- package/dist/component/server/types.js.map +0 -1
- package/dist/component/server/users.js +0 -123
- package/dist/component/server/users.js.map +0 -1
- package/dist/component/server/utils.js +0 -140
- package/dist/component/server/utils.js.map +0 -1
- package/dist/core/types.d.ts +0 -361
- package/dist/core/types.d.ts.map +0 -1
- package/dist/factors/device.js +0 -104
- package/dist/factors/device.js.map +0 -1
- package/dist/factors/passkey.js.map +0 -1
- package/dist/factors/totp.js.map +0 -1
- package/dist/providers/anonymous.d.ts.map +0 -1
- package/dist/providers/anonymous.js.map +0 -1
- package/dist/providers/credentials.d.ts.map +0 -1
- package/dist/providers/credentials.js.map +0 -1
- package/dist/providers/device.d.ts.map +0 -1
- package/dist/providers/device.js.map +0 -1
- package/dist/providers/email.d.ts.map +0 -1
- package/dist/providers/email.js.map +0 -1
- package/dist/providers/oauth.d.ts +0 -69
- package/dist/providers/oauth.d.ts.map +0 -1
- package/dist/providers/oauth.js +0 -43
- package/dist/providers/oauth.js.map +0 -1
- package/dist/providers/passkey.d.ts.map +0 -1
- package/dist/providers/passkey.js.map +0 -1
- package/dist/providers/password.d.ts.map +0 -1
- package/dist/providers/password.js.map +0 -1
- package/dist/providers/phone.d.ts.map +0 -1
- package/dist/providers/phone.js.map +0 -1
- package/dist/providers/sso.d.ts.map +0 -1
- package/dist/providers/sso.js.map +0 -1
- package/dist/providers/totp.d.ts.map +0 -1
- package/dist/providers/totp.js.map +0 -1
- package/dist/runtime/browser.js +0 -68
- package/dist/runtime/browser.js.map +0 -1
- package/dist/runtime/invite.js.map +0 -1
- package/dist/runtime/proxy.js +0 -70
- package/dist/runtime/proxy.js.map +0 -1
- package/dist/runtime/storage.js +0 -37
- package/dist/runtime/storage.js.map +0 -1
- package/dist/server/auth.d.ts.map +0 -1
- package/dist/server/auth.js.map +0 -1
- package/dist/server/config.d.ts +0 -1
- package/dist/server/config.js.map +0 -1
- package/dist/server/context.d.ts +0 -1
- package/dist/server/context.js.map +0 -1
- package/dist/server/cookies.d.ts +0 -1
- package/dist/server/cookies.js.map +0 -1
- package/dist/server/core.d.ts +0 -1315
- package/dist/server/core.d.ts.map +0 -1
- package/dist/server/core.js.map +0 -1
- package/dist/server/crypto.d.ts +0 -8
- package/dist/server/crypto.d.ts.map +0 -1
- package/dist/server/crypto.js.map +0 -1
- package/dist/server/db.d.ts +0 -1
- package/dist/server/db.js.map +0 -1
- package/dist/server/device.d.ts +0 -1
- package/dist/server/device.js.map +0 -1
- package/dist/server/enterprise/config.d.ts +0 -1
- package/dist/server/enterprise/config.js.map +0 -1
- package/dist/server/enterprise/domain.d.ts +0 -401
- package/dist/server/enterprise/domain.d.ts.map +0 -1
- package/dist/server/enterprise/domain.js +0 -974
- package/dist/server/enterprise/domain.js.map +0 -1
- package/dist/server/enterprise/http.d.ts +0 -26
- package/dist/server/enterprise/http.d.ts.map +0 -1
- package/dist/server/enterprise/http.js +0 -787
- package/dist/server/enterprise/http.js.map +0 -1
- package/dist/server/enterprise/oidc.d.ts +0 -1
- package/dist/server/enterprise/oidc.js +0 -248
- package/dist/server/enterprise/oidc.js.map +0 -1
- package/dist/server/enterprise/policy.d.ts +0 -1
- package/dist/server/enterprise/policy.js +0 -85
- package/dist/server/enterprise/policy.js.map +0 -1
- package/dist/server/enterprise/saml.d.ts +0 -1
- package/dist/server/enterprise/saml.js +0 -338
- package/dist/server/enterprise/saml.js.map +0 -1
- package/dist/server/enterprise/scim.d.ts +0 -1
- package/dist/server/enterprise/scim.js +0 -97
- package/dist/server/enterprise/scim.js.map +0 -1
- package/dist/server/enterprise/shared.d.ts +0 -5
- package/dist/server/enterprise/shared.d.ts.map +0 -1
- package/dist/server/enterprise/shared.js +0 -51
- package/dist/server/enterprise/shared.js.map +0 -1
- package/dist/server/enterprise/validators.d.ts +0 -1
- package/dist/server/enterprise/validators.js +0 -60
- package/dist/server/enterprise/validators.js.map +0 -1
- package/dist/server/http.d.ts.map +0 -1
- package/dist/server/http.js.map +0 -1
- package/dist/server/identity.d.ts +0 -1
- package/dist/server/identity.js.map +0 -1
- package/dist/server/keys.d.ts +0 -1
- package/dist/server/keys.js.map +0 -1
- package/dist/server/limits.d.ts +0 -1
- package/dist/server/limits.js.map +0 -1
- package/dist/server/mounts.d.ts.map +0 -1
- package/dist/server/mounts.js.map +0 -1
- package/dist/server/mutations/account.d.ts +0 -29
- package/dist/server/mutations/account.d.ts.map +0 -1
- package/dist/server/mutations/account.js.map +0 -1
- package/dist/server/mutations/code.d.ts +0 -30
- package/dist/server/mutations/code.d.ts.map +0 -1
- package/dist/server/mutations/code.js.map +0 -1
- package/dist/server/mutations/index.d.ts +0 -14
- package/dist/server/mutations/invalidate.d.ts +0 -20
- package/dist/server/mutations/invalidate.d.ts.map +0 -1
- package/dist/server/mutations/invalidate.js.map +0 -1
- package/dist/server/mutations/oauth.d.ts +0 -30
- package/dist/server/mutations/oauth.d.ts.map +0 -1
- package/dist/server/mutations/oauth.js.map +0 -1
- package/dist/server/mutations/refresh.d.ts +0 -21
- package/dist/server/mutations/refresh.d.ts.map +0 -1
- package/dist/server/mutations/refresh.js.map +0 -1
- package/dist/server/mutations/register.d.ts +0 -38
- package/dist/server/mutations/register.d.ts.map +0 -1
- package/dist/server/mutations/register.js.map +0 -1
- package/dist/server/mutations/retrieve.d.ts +0 -33
- package/dist/server/mutations/retrieve.d.ts.map +0 -1
- package/dist/server/mutations/retrieve.js.map +0 -1
- package/dist/server/mutations/signature.d.ts +0 -21
- package/dist/server/mutations/signature.d.ts.map +0 -1
- package/dist/server/mutations/signature.js.map +0 -1
- package/dist/server/mutations/signin.d.ts +0 -22
- package/dist/server/mutations/signin.d.ts.map +0 -1
- package/dist/server/mutations/signin.js.map +0 -1
- package/dist/server/mutations/signout.d.ts +0 -16
- package/dist/server/mutations/signout.d.ts.map +0 -1
- package/dist/server/mutations/signout.js.map +0 -1
- package/dist/server/mutations/store/refs.d.ts +0 -12
- package/dist/server/mutations/store/refs.d.ts.map +0 -1
- package/dist/server/mutations/store/refs.js.map +0 -1
- package/dist/server/mutations/store.d.ts +0 -306
- package/dist/server/mutations/store.d.ts.map +0 -1
- package/dist/server/mutations/store.js.map +0 -1
- package/dist/server/mutations/verifier.d.ts +0 -13
- package/dist/server/mutations/verifier.d.ts.map +0 -1
- package/dist/server/mutations/verifier.js.map +0 -1
- package/dist/server/mutations/verify.d.ts +0 -26
- package/dist/server/mutations/verify.d.ts.map +0 -1
- package/dist/server/mutations/verify.js.map +0 -1
- package/dist/server/oauth.d.ts +0 -1
- package/dist/server/oauth.js +0 -242
- package/dist/server/oauth.js.map +0 -1
- package/dist/server/passkey.d.ts +0 -27
- package/dist/server/passkey.d.ts.map +0 -1
- package/dist/server/passkey.js.map +0 -1
- package/dist/server/redirects.d.ts +0 -1
- package/dist/server/redirects.js.map +0 -1
- package/dist/server/refresh.d.ts +0 -1
- package/dist/server/refresh.js.map +0 -1
- package/dist/server/runtime.d.ts.map +0 -1
- package/dist/server/runtime.js.map +0 -1
- package/dist/server/sessions.d.ts +0 -1
- package/dist/server/sessions.js.map +0 -1
- package/dist/server/signin.d.ts +0 -1
- package/dist/server/signin.js.map +0 -1
- package/dist/server/ssr.d.ts.map +0 -1
- package/dist/server/ssr.js +0 -777
- package/dist/server/ssr.js.map +0 -1
- package/dist/server/templates.d.ts +0 -1
- package/dist/server/templates.js.map +0 -1
- package/dist/server/tokens.d.ts +0 -1
- package/dist/server/tokens.js.map +0 -1
- package/dist/server/totp.d.ts +0 -1
- package/dist/server/totp.js.map +0 -1
- package/dist/server/types.d.ts.map +0 -1
- package/dist/server/types.js.map +0 -1
- package/dist/server/users.d.ts +0 -1
- package/dist/server/users.js.map +0 -1
- package/dist/server/utils.d.ts +0 -1
- package/dist/server/utils.js +0 -140
- package/dist/server/utils.js.map +0 -1
- package/src/authorization/index.ts +0 -83
- package/src/cli/bin.ts +0 -5
- package/src/cli/command.ts +0 -70
- package/src/cli/index.ts +0 -1112
- package/src/cli/keys.ts +0 -23
- package/src/client/core/types.ts +0 -437
- package/src/client/factors/device.ts +0 -158
- package/src/client/factors/passkey.ts +0 -279
- package/src/client/factors/totp.ts +0 -150
- package/src/client/index.ts +0 -1124
- package/src/client/runtime/browser.ts +0 -112
- package/src/client/runtime/invite.ts +0 -63
- package/src/client/runtime/proxy.ts +0 -111
- package/src/client/runtime/storage.ts +0 -79
- package/src/component/_generated/api.ts +0 -96
- package/src/component/_generated/component.ts +0 -3774
- package/src/component/_generated/dataModel.ts +0 -60
- package/src/component/_generated/server.ts +0 -156
- package/src/component/convex.config.ts +0 -5
- package/src/component/functions.ts +0 -104
- package/src/component/index.ts +0 -42
- package/src/component/model.ts +0 -449
- package/src/component/public/enterprise/audit.ts +0 -125
- package/src/component/public/enterprise/core.ts +0 -355
- package/src/component/public/enterprise/domains.ts +0 -327
- package/src/component/public/enterprise/scim.ts +0 -397
- package/src/component/public/enterprise/secrets.ts +0 -133
- package/src/component/public/enterprise/webhooks.ts +0 -307
- package/src/component/public/factors/devices.ts +0 -224
- package/src/component/public/factors/passkeys.ts +0 -243
- package/src/component/public/factors/totp.ts +0 -259
- package/src/component/public/groups/core.ts +0 -481
- package/src/component/public/groups/invites.ts +0 -608
- package/src/component/public/groups/members.ts +0 -410
- package/src/component/public/identity/accounts.ts +0 -207
- package/src/component/public/identity/codes.ts +0 -149
- package/src/component/public/identity/sessions.ts +0 -210
- package/src/component/public/identity/tokens.ts +0 -251
- package/src/component/public/identity/users.ts +0 -355
- package/src/component/public/identity/verifiers.ts +0 -158
- package/src/component/public/security/keys.ts +0 -366
- package/src/component/public/security/limits.ts +0 -174
- package/src/component/public.ts +0 -27
- package/src/component/schema.ts +0 -505
- package/src/providers/anonymous.ts +0 -99
- package/src/providers/credentials.ts +0 -102
- package/src/providers/device.ts +0 -87
- package/src/providers/email.ts +0 -99
- package/src/providers/index.ts +0 -31
- package/src/providers/oauth.ts +0 -117
- package/src/providers/passkey.ts +0 -77
- package/src/providers/password.ts +0 -441
- package/src/providers/phone.ts +0 -93
- package/src/providers/sso.ts +0 -54
- package/src/providers/totp.ts +0 -62
- package/src/samlify.d.ts +0 -53
- package/src/server/auth.ts +0 -949
- package/src/server/config.ts +0 -200
- package/src/server/context.ts +0 -90
- package/src/server/cookies.ts +0 -49
- package/src/server/core.ts +0 -2004
- package/src/server/crypto.ts +0 -90
- package/src/server/db.ts +0 -203
- package/src/server/device.ts +0 -254
- package/src/server/enterprise/config.ts +0 -51
- package/src/server/enterprise/domain.ts +0 -1739
- package/src/server/enterprise/http.ts +0 -1331
- package/src/server/enterprise/oidc.ts +0 -500
- package/src/server/enterprise/policy.ts +0 -128
- package/src/server/enterprise/saml.ts +0 -578
- package/src/server/enterprise/scim.ts +0 -135
- package/src/server/enterprise/shared.ts +0 -134
- package/src/server/enterprise/validators.ts +0 -93
- package/src/server/http.ts +0 -790
- package/src/server/identity.ts +0 -18
- package/src/server/index.ts +0 -40
- package/src/server/keys.ts +0 -158
- package/src/server/limits.ts +0 -107
- package/src/server/mounts.ts +0 -924
- package/src/server/mutations/account.ts +0 -62
- package/src/server/mutations/code.ts +0 -119
- package/src/server/mutations/index.ts +0 -13
- package/src/server/mutations/invalidate.ts +0 -50
- package/src/server/mutations/oauth.ts +0 -243
- package/src/server/mutations/refresh.ts +0 -299
- package/src/server/mutations/register.ts +0 -155
- package/src/server/mutations/retrieve.ts +0 -109
- package/src/server/mutations/signature.ts +0 -57
- package/src/server/mutations/signin.ts +0 -54
- package/src/server/mutations/signout.ts +0 -43
- package/src/server/mutations/store/refs.ts +0 -10
- package/src/server/mutations/store.ts +0 -123
- package/src/server/mutations/verifier.ts +0 -34
- package/src/server/mutations/verify.ts +0 -200
- package/src/server/oauth.ts +0 -418
- package/src/server/passkey.ts +0 -838
- package/src/server/redirects.ts +0 -59
- package/src/server/refresh.ts +0 -218
- package/src/server/runtime.ts +0 -918
- package/src/server/sessions.ts +0 -132
- package/src/server/signin.ts +0 -445
- package/src/server/ssr.ts +0 -1747
- package/src/server/templates.ts +0 -82
- package/src/server/tokens.ts +0 -35
- package/src/server/totp.ts +0 -399
- package/src/server/types.ts +0 -1942
- package/src/server/users.ts +0 -291
- package/src/server/utils.ts +0 -220
- /package/dist/{runtime → client/runtime}/invite.js +0 -0
package/dist/server/oauth.js
DELETED
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { isLocalHost, logWithLevel } from "./utils.js";
|
|
2
|
-
import { SHARED_COOKIE_OPTIONS } from "./cookies.js";
|
|
3
|
-
import { Fx } from "@robelest/fx";
|
|
4
|
-
import { Cv } from "@robelest/fx/convex";
|
|
5
|
-
import * as arctic from "arctic";
|
|
6
|
-
|
|
7
|
-
//#region src/server/oauth.ts
|
|
8
|
-
/**
|
|
9
|
-
* Arctic-based OAuth flow implementation.
|
|
10
|
-
*
|
|
11
|
-
* Uses Arctic for OAuth provider integration.
|
|
12
|
-
*
|
|
13
|
-
* All functions return `Fx<A, ConvexError<any>>` composed via `Fx.gen` pipelines.
|
|
14
|
-
*
|
|
15
|
-
* @internal
|
|
16
|
-
* @module
|
|
17
|
-
*/
|
|
18
|
-
const COOKIE_TTL = 900;
|
|
19
|
-
function oauthCookieName(type, providerId) {
|
|
20
|
-
return (!isLocalHost(process.env.CONVEX_SITE_URL) ? "__Host-" : "") + providerId + "OAuth" + type;
|
|
21
|
-
}
|
|
22
|
-
function createCookie(type, providerId, value) {
|
|
23
|
-
const expires = /* @__PURE__ */ new Date();
|
|
24
|
-
expires.setTime(expires.getTime() + COOKIE_TTL * 1e3);
|
|
25
|
-
return {
|
|
26
|
-
name: oauthCookieName(type, providerId),
|
|
27
|
-
value,
|
|
28
|
-
options: {
|
|
29
|
-
...SHARED_COOKIE_OPTIONS,
|
|
30
|
-
expires
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function clearCookie(type, providerId) {
|
|
35
|
-
return {
|
|
36
|
-
name: oauthCookieName(type, providerId),
|
|
37
|
-
value: "",
|
|
38
|
-
options: {
|
|
39
|
-
...SHARED_COOKIE_OPTIONS,
|
|
40
|
-
maxAge: 0
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Creates a signature string from the OAuth state parameters.
|
|
46
|
-
* This is stored in the verifier table and validated during callback.
|
|
47
|
-
*/
|
|
48
|
-
/** @internal */
|
|
49
|
-
function getAuthorizationSignature({ codeVerifier, state }) {
|
|
50
|
-
return [codeVerifier, state].filter((param) => param !== void 0).join(" ");
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Detect whether an Arctic provider uses PKCE by checking the arity
|
|
54
|
-
* of `createAuthorizationURL`. PKCE providers take 3 args
|
|
55
|
-
* (state, codeVerifier, scopes), non-PKCE take 2 (state, scopes).
|
|
56
|
-
*/
|
|
57
|
-
function isPKCEProvider(provider) {
|
|
58
|
-
return typeof provider.createAuthorizationURL === "function" && provider.createAuthorizationURL.length >= 3;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Exchange the authorization code for tokens via Arctic.
|
|
62
|
-
* Maps Arctic-specific errors to typed `ConvexError<any>` failures.
|
|
63
|
-
*/
|
|
64
|
-
function exchangeCode(arcticProvider, code, codeVerifier) {
|
|
65
|
-
return Fx.from({
|
|
66
|
-
ok: () => isPKCEProvider(arcticProvider) ? arcticProvider.validateAuthorizationCode(code, codeVerifier) : arcticProvider.validateAuthorizationCode(code),
|
|
67
|
-
err: (e) => {
|
|
68
|
-
if (e instanceof arctic.OAuth2RequestError) return Cv.error({
|
|
69
|
-
code: "OAUTH_PROVIDER_ERROR",
|
|
70
|
-
message: `Token exchange failed: ${e.code}`
|
|
71
|
-
});
|
|
72
|
-
if (e instanceof arctic.ArcticFetchError) return Cv.error({
|
|
73
|
-
code: "OAUTH_PROVIDER_ERROR",
|
|
74
|
-
message: `Network error during token exchange: ${e.message}`
|
|
75
|
-
});
|
|
76
|
-
return Cv.error({
|
|
77
|
-
code: "OAUTH_PROVIDER_ERROR",
|
|
78
|
-
message: `Unexpected error during token exchange: ${e instanceof Error ? e.message : String(e)}`
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
}).pipe(Fx.chain((tokens) => {
|
|
82
|
-
return Fx.succeed(tokens);
|
|
83
|
-
}));
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Extract the user profile from tokens using the config callback,
|
|
87
|
-
* OIDC auto-decode, or fail if neither is available.
|
|
88
|
-
*/
|
|
89
|
-
function extractProfile(providerId, oauthConfig, tokens) {
|
|
90
|
-
const hasIdToken = "id_token" in tokens.data && typeof tokens.data.id_token === "string";
|
|
91
|
-
const profileSource = oauthConfig.profile ? { source: "callback" } : hasIdToken ? { source: "idToken" } : { source: "missing" };
|
|
92
|
-
return Fx.match(profileSource, profileSource.source, {
|
|
93
|
-
callback: (_profileSource) => Fx.from({
|
|
94
|
-
ok: () => oauthConfig.profile(tokens),
|
|
95
|
-
err: (e) => Cv.error({
|
|
96
|
-
code: "OAUTH_INVALID_PROFILE",
|
|
97
|
-
message: `Profile callback threw: ${e instanceof Error ? e.message : String(e)}`
|
|
98
|
-
})
|
|
99
|
-
}),
|
|
100
|
-
idToken: (_profileSource) => {
|
|
101
|
-
const claims = arctic.decodeIdToken(tokens.idToken());
|
|
102
|
-
return Fx.succeed({
|
|
103
|
-
id: claims.sub ?? crypto.randomUUID(),
|
|
104
|
-
name: claims.name ?? void 0,
|
|
105
|
-
email: claims.email ?? void 0,
|
|
106
|
-
image: claims.picture ?? void 0
|
|
107
|
-
});
|
|
108
|
-
},
|
|
109
|
-
missing: (_profileSource) => Cv.fail({
|
|
110
|
-
code: "OAUTH_INVALID_PROFILE",
|
|
111
|
-
message: `Provider "${providerId}" does not return an ID token. Add a \`profile\` callback in the OAuth() config to extract user info from the access token.`
|
|
112
|
-
})
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Validate that the profile has a non-empty string `id`.
|
|
117
|
-
*/
|
|
118
|
-
function validateProfileId(providerId, profile) {
|
|
119
|
-
return typeof profile.id === "string" && profile.id ? Fx.succeed(profile) : Cv.fail({
|
|
120
|
-
code: "OAUTH_INVALID_PROFILE",
|
|
121
|
-
message: `The profile callback for "${providerId}" must return an object with a string \`id\` field.`
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Create an OAuth authorization URL using an Arctic provider.
|
|
126
|
-
*
|
|
127
|
-
* Handles PKCE detection, state generation, and cookie creation.
|
|
128
|
-
*/
|
|
129
|
-
/** @internal */
|
|
130
|
-
async function createOAuthAuthorizationURL(providerId, arcticProvider, oauthConfig) {
|
|
131
|
-
const state = arctic.generateState();
|
|
132
|
-
const cookies = [];
|
|
133
|
-
let codeVerifier;
|
|
134
|
-
const scopes = oauthConfig.scopes ?? [];
|
|
135
|
-
let url;
|
|
136
|
-
if (isPKCEProvider(arcticProvider)) {
|
|
137
|
-
codeVerifier = arctic.generateCodeVerifier();
|
|
138
|
-
url = arcticProvider.createAuthorizationURL(state, codeVerifier, scopes);
|
|
139
|
-
cookies.push(createCookie("pkce", providerId, codeVerifier));
|
|
140
|
-
} else url = arcticProvider.createAuthorizationURL(state, scopes);
|
|
141
|
-
cookies.push(createCookie("state", providerId, state));
|
|
142
|
-
if (oauthConfig.nonce === true) {
|
|
143
|
-
const nonce = arctic.generateState();
|
|
144
|
-
url.searchParams.set("nonce", nonce);
|
|
145
|
-
cookies.push(createCookie("nonce", providerId, nonce));
|
|
146
|
-
}
|
|
147
|
-
logWithLevel("DEBUG", "OAuth authorization URL created", {
|
|
148
|
-
url: url.toString(),
|
|
149
|
-
providerId,
|
|
150
|
-
hasPKCE: !!codeVerifier
|
|
151
|
-
});
|
|
152
|
-
const signature = getAuthorizationSignature({
|
|
153
|
-
codeVerifier,
|
|
154
|
-
state
|
|
155
|
-
});
|
|
156
|
-
return {
|
|
157
|
-
redirect: url.toString(),
|
|
158
|
-
cookies,
|
|
159
|
-
signature
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
/**
|
|
163
|
-
* Handle the OAuth callback: validate state, exchange code for tokens,
|
|
164
|
-
* extract profile.
|
|
165
|
-
*
|
|
166
|
-
* Returns `Fx<CallbackResult, ConvexError<any>>` composed via `Fx.gen`.
|
|
167
|
-
*/
|
|
168
|
-
/** @internal */
|
|
169
|
-
function handleOAuthCallback(providerId, arcticProvider, oauthConfig, params, cookies) {
|
|
170
|
-
return Fx.gen(function* () {
|
|
171
|
-
const resCookies = [];
|
|
172
|
-
const storedState = cookies[oauthCookieName("state", providerId)];
|
|
173
|
-
const returnedState = params.state;
|
|
174
|
-
yield* Fx.guard(!storedState || !returnedState || storedState !== returnedState, Cv.fail({
|
|
175
|
-
code: "OAUTH_INVALID_STATE",
|
|
176
|
-
message: "Invalid OAuth state. Please try signing in again."
|
|
177
|
-
}));
|
|
178
|
-
resCookies.push(clearCookie("state", providerId));
|
|
179
|
-
if (params.error) {
|
|
180
|
-
const cause = {
|
|
181
|
-
providerId,
|
|
182
|
-
error: params.error,
|
|
183
|
-
error_description: params.error_description
|
|
184
|
-
};
|
|
185
|
-
logWithLevel("DEBUG", "OAuthCallbackError", cause);
|
|
186
|
-
yield* Cv.fail({
|
|
187
|
-
code: "OAUTH_PROVIDER_ERROR",
|
|
188
|
-
message: "OAuth provider returned an error",
|
|
189
|
-
cause: JSON.stringify(cause)
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
const code = yield* params.code != null ? Fx.succeed(params.code) : Cv.fail({
|
|
193
|
-
code: "OAUTH_PROVIDER_ERROR",
|
|
194
|
-
message: "Missing authorization code in callback"
|
|
195
|
-
});
|
|
196
|
-
let codeVerifier;
|
|
197
|
-
if (isPKCEProvider(arcticProvider)) {
|
|
198
|
-
const pkceCookieName = oauthCookieName("pkce", providerId);
|
|
199
|
-
codeVerifier = yield* cookies[pkceCookieName] != null ? Fx.succeed(cookies[pkceCookieName]) : Cv.fail({
|
|
200
|
-
code: "OAUTH_MISSING_VERIFIER",
|
|
201
|
-
message: "Missing PKCE verifier cookie for OAuth callback"
|
|
202
|
-
});
|
|
203
|
-
resCookies.push(clearCookie("pkce", providerId));
|
|
204
|
-
}
|
|
205
|
-
let nonce;
|
|
206
|
-
if (oauthConfig.nonce === true) {
|
|
207
|
-
const nonceCookieName = oauthCookieName("nonce", providerId);
|
|
208
|
-
nonce = yield* cookies[nonceCookieName] != null ? Fx.succeed(cookies[nonceCookieName]) : Cv.fail({
|
|
209
|
-
code: "OAUTH_PROVIDER_ERROR",
|
|
210
|
-
message: "Missing nonce cookie for OAuth callback"
|
|
211
|
-
});
|
|
212
|
-
resCookies.push(clearCookie("nonce", providerId));
|
|
213
|
-
}
|
|
214
|
-
const tokens = yield* exchangeCode(arcticProvider, code, codeVerifier);
|
|
215
|
-
if (oauthConfig.validateTokens !== void 0) yield* Fx.from({
|
|
216
|
-
ok: () => oauthConfig.validateTokens(tokens, { nonce }),
|
|
217
|
-
err: (e) => Cv.error({
|
|
218
|
-
code: "OAUTH_PROVIDER_ERROR",
|
|
219
|
-
message: `Token validation failed: ${e instanceof Error ? e.message : String(e)}`
|
|
220
|
-
})
|
|
221
|
-
});
|
|
222
|
-
const profile = yield* validateProfileId(providerId, yield* extractProfile(providerId, oauthConfig, tokens));
|
|
223
|
-
logWithLevel("DEBUG", "OAuth callback profile extracted", {
|
|
224
|
-
providerId,
|
|
225
|
-
profileId: profile.id
|
|
226
|
-
});
|
|
227
|
-
const signature = getAuthorizationSignature({
|
|
228
|
-
codeVerifier,
|
|
229
|
-
state: storedState
|
|
230
|
-
});
|
|
231
|
-
return {
|
|
232
|
-
profile,
|
|
233
|
-
providerAccountId: profile.id,
|
|
234
|
-
cookies: resCookies,
|
|
235
|
-
signature
|
|
236
|
-
};
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
//#endregion
|
|
241
|
-
export { createOAuthAuthorizationURL, getAuthorizationSignature, handleOAuthCallback };
|
|
242
|
-
//# sourceMappingURL=oauth.js.map
|
package/dist/server/oauth.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","names":[],"sources":["../../src/server/oauth.ts"],"sourcesContent":["/**\n * Arctic-based OAuth flow implementation.\n *\n * Uses Arctic for OAuth provider integration.\n *\n * All functions return `Fx<A, ConvexError<any>>` composed via `Fx.gen` pipelines.\n *\n * @internal\n * @module\n */\n\nimport { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport * as arctic from \"arctic\";\nimport type { ConvexError } from \"convex/values\";\n\nimport { SHARED_COOKIE_OPTIONS } from \"./cookies\";\nimport type { OAuthProfile } from \"./types\";\nimport { logWithLevel } from \"./utils\";\nimport { isLocalHost } from \"./utils\";\n\ntype OAuthProviderConfigLike = {\n scopes?: string[];\n profile?: (tokens: arctic.OAuth2Tokens) => Promise<OAuthProfile>;\n nonce?: boolean;\n validateTokens?: (\n tokens: arctic.OAuth2Tokens,\n ctx: { nonce?: string },\n ) => Promise<void>;\n};\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/** A cookie to be set on the HTTP response. */\n/** @internal */\nexport interface OAuthCookie {\n name: string;\n value: string;\n options: Record<string, unknown>;\n}\n\n/** Result of creating an authorization URL. */\n/** @internal */\nexport interface AuthorizationResult {\n redirect: string;\n cookies: OAuthCookie[];\n signature: string;\n}\n\n/** Result of handling an OAuth callback. */\n/** @internal */\nexport interface CallbackResult {\n profile: OAuthProfile;\n providerAccountId: string;\n cookies: OAuthCookie[];\n signature: string;\n}\n\n// ============================================================================\n// Cookie helpers\n// ============================================================================\n\nconst COOKIE_TTL = 60 * 15; // 15 minutes\n\nfunction oauthCookieName(type: \"state\" | \"pkce\" | \"nonce\", providerId: string) {\n const prefix = !isLocalHost(process.env.CONVEX_SITE_URL) ? \"__Host-\" : \"\";\n return prefix + providerId + \"OAuth\" + type;\n}\n\nfunction createCookie(\n type: \"state\" | \"pkce\" | \"nonce\",\n providerId: string,\n value: string,\n): OAuthCookie {\n const expires = new Date();\n expires.setTime(expires.getTime() + COOKIE_TTL * 1000);\n return {\n name: oauthCookieName(type, providerId),\n value,\n options: { ...SHARED_COOKIE_OPTIONS, expires },\n };\n}\n\nfunction clearCookie(\n type: \"state\" | \"pkce\" | \"nonce\",\n providerId: string,\n): OAuthCookie {\n return {\n name: oauthCookieName(type, providerId),\n value: \"\",\n options: { ...SHARED_COOKIE_OPTIONS, maxAge: 0 },\n };\n}\n\n// ============================================================================\n// Signature (ConvexAuth-specific verifier mechanism)\n// ============================================================================\n\n/**\n * Creates a signature string from the OAuth state parameters.\n * This is stored in the verifier table and validated during callback.\n */\n/** @internal */\nexport function getAuthorizationSignature({\n codeVerifier,\n state,\n}: {\n codeVerifier?: string;\n state?: string;\n}) {\n return [codeVerifier, state].filter((param) => param !== undefined).join(\" \");\n}\n\n// ============================================================================\n// PKCE Detection\n// ============================================================================\n\n/**\n * Detect whether an Arctic provider uses PKCE by checking the arity\n * of `createAuthorizationURL`. PKCE providers take 3 args\n * (state, codeVerifier, scopes), non-PKCE take 2 (state, scopes).\n */\nfunction isPKCEProvider(provider: any): boolean {\n return (\n typeof provider.createAuthorizationURL === \"function\" &&\n provider.createAuthorizationURL.length >= 3\n );\n}\n\n// ============================================================================\n// Token exchange — wraps Arctic's validateAuthorizationCode\n// ============================================================================\n\n/**\n * Exchange the authorization code for tokens via Arctic.\n * Maps Arctic-specific errors to typed `ConvexError<any>` failures.\n */\nfunction exchangeCode(\n arcticProvider: any,\n code: string,\n codeVerifier: string | undefined,\n): Fx<arctic.OAuth2Tokens, ConvexError<any>> {\n return Fx.from({\n ok: () =>\n isPKCEProvider(arcticProvider)\n ? arcticProvider.validateAuthorizationCode(code, codeVerifier)\n : arcticProvider.validateAuthorizationCode(code),\n err: (e) => {\n if (e instanceof arctic.OAuth2RequestError) {\n return Cv.error({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: `Token exchange failed: ${e.code}`,\n });\n }\n if (e instanceof arctic.ArcticFetchError) {\n return Cv.error({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: `Network error during token exchange: ${e.message}`,\n });\n }\n // Unknown error — treat as unrecoverable defect; we surface it as\n // an ConvexError<any> here so the pipeline type stays Fx<_, ConvexError<any>>.\n // The original `throw e` re-throw is replicated via Fx.fatal below.\n return Cv.error({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: `Unexpected error during token exchange: ${e instanceof Error ? e.message : String(e)}`,\n });\n },\n }).pipe(\n Fx.chain((tokens) => {\n // If the original error was neither OAuth2RequestError nor\n // ArcticFetchError the old code re-threw it raw. We replicate that\n // by checking whether we created an \"Unexpected\" marker message\n // — but since `Fx.from` already mapped it, we just pass through.\n return Fx.succeed(tokens);\n }),\n );\n}\n\n/**\n * Extract the user profile from tokens using the config callback,\n * OIDC auto-decode, or fail if neither is available.\n */\nfunction extractProfile(\n providerId: string,\n oauthConfig: OAuthProviderConfigLike,\n tokens: arctic.OAuth2Tokens,\n): Fx<OAuthProfile, ConvexError<any>> {\n const hasIdToken =\n \"id_token\" in tokens.data &&\n typeof (tokens.data as any).id_token === \"string\";\n const profileSource = oauthConfig.profile\n ? { source: \"callback\" as const }\n : hasIdToken\n ? { source: \"idToken\" as const }\n : { source: \"missing\" as const };\n\n return Fx.match(profileSource, profileSource.source, {\n callback: (_profileSource) =>\n Fx.from({\n ok: () => oauthConfig.profile!(tokens),\n err: (e) =>\n Cv.error({\n code: \"OAUTH_INVALID_PROFILE\",\n message: `Profile callback threw: ${e instanceof Error ? e.message : String(e)}`,\n }),\n }),\n idToken: (_profileSource) => {\n const claims = arctic.decodeIdToken(tokens.idToken()) as Record<\n string,\n unknown\n >;\n return Fx.succeed({\n id: (claims.sub as string) ?? crypto.randomUUID(),\n name: (claims.name as string) ?? undefined,\n email: (claims.email as string) ?? undefined,\n image: (claims.picture as string) ?? undefined,\n });\n },\n missing: (_profileSource) =>\n Cv.fail({\n code: \"OAUTH_INVALID_PROFILE\",\n message:\n `Provider \"${providerId}\" does not return an ID token. ` +\n `Add a \\`profile\\` callback in the OAuth() config to extract user info from the access token.`,\n }),\n });\n}\n\n/**\n * Validate that the profile has a non-empty string `id`.\n */\nfunction validateProfileId(\n providerId: string,\n profile: OAuthProfile,\n): Fx<OAuthProfile, ConvexError<any>> {\n return typeof profile.id === \"string\" && profile.id\n ? Fx.succeed(profile)\n : Cv.fail({\n code: \"OAUTH_INVALID_PROFILE\",\n message: `The profile callback for \"${providerId}\" must return an object with a string \\`id\\` field.`,\n });\n}\n\n// ============================================================================\n// Authorization URL creation\n// ============================================================================\n\n/**\n * Create an OAuth authorization URL using an Arctic provider.\n *\n * Handles PKCE detection, state generation, and cookie creation.\n */\n/** @internal */\nexport async function createOAuthAuthorizationURL(\n providerId: string,\n arcticProvider: any,\n oauthConfig: OAuthProviderConfigLike,\n): Promise<AuthorizationResult> {\n const state = arctic.generateState();\n const cookies: OAuthCookie[] = [];\n let codeVerifier: string | undefined;\n\n const scopes = oauthConfig.scopes ?? [];\n\n let url: URL;\n\n if (isPKCEProvider(arcticProvider)) {\n codeVerifier = arctic.generateCodeVerifier();\n url = arcticProvider.createAuthorizationURL(state, codeVerifier, scopes);\n cookies.push(createCookie(\"pkce\", providerId, codeVerifier));\n } else {\n url = arcticProvider.createAuthorizationURL(state, scopes);\n }\n\n cookies.push(createCookie(\"state\", providerId, state));\n\n if (oauthConfig.nonce === true) {\n const nonce = arctic.generateState();\n url.searchParams.set(\"nonce\", nonce);\n cookies.push(createCookie(\"nonce\", providerId, nonce));\n }\n\n logWithLevel(\"DEBUG\", \"OAuth authorization URL created\", {\n url: url.toString(),\n providerId,\n hasPKCE: !!codeVerifier,\n });\n\n const signature = getAuthorizationSignature({ codeVerifier, state });\n\n return {\n redirect: url.toString(),\n cookies,\n signature,\n };\n}\n\n// ============================================================================\n// OAuth callback handling\n// ============================================================================\n\n/**\n * Handle the OAuth callback: validate state, exchange code for tokens,\n * extract profile.\n *\n * Returns `Fx<CallbackResult, ConvexError<any>>` composed via `Fx.gen`.\n */\n/** @internal */\nexport function handleOAuthCallback(\n providerId: string,\n arcticProvider: any,\n oauthConfig: OAuthProviderConfigLike,\n params: Record<string, string>,\n cookies: Record<string, string | undefined>,\n): Fx<CallbackResult, ConvexError<any>> {\n return Fx.gen(function* () {\n const resCookies: OAuthCookie[] = [];\n\n // 1. Validate state\n const stateCookieName = oauthCookieName(\"state\", providerId);\n const storedState = cookies[stateCookieName];\n const returnedState = params.state;\n\n yield* Fx.guard(\n !storedState || !returnedState || storedState !== returnedState,\n Cv.fail({\n code: \"OAUTH_INVALID_STATE\",\n message: \"Invalid OAuth state. Please try signing in again.\",\n }),\n );\n resCookies.push(clearCookie(\"state\", providerId));\n\n // Check for error from provider\n if (params.error) {\n const cause = {\n providerId,\n error: params.error,\n error_description: params.error_description,\n };\n logWithLevel(\"DEBUG\", \"OAuthCallbackError\", cause);\n yield* Cv.fail({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: \"OAuth provider returned an error\",\n cause: JSON.stringify(cause),\n });\n }\n\n // 2. Get code\n const code = yield* params.code != null\n ? Fx.succeed(params.code)\n : Cv.fail({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: \"Missing authorization code in callback\",\n });\n\n // 3. Read PKCE verifier from cookie if applicable\n let codeVerifier: string | undefined;\n if (isPKCEProvider(arcticProvider)) {\n const pkceCookieName = oauthCookieName(\"pkce\", providerId);\n codeVerifier = yield* cookies[pkceCookieName] != null\n ? Fx.succeed(cookies[pkceCookieName]!)\n : Cv.fail({\n code: \"OAUTH_MISSING_VERIFIER\",\n message: \"Missing PKCE verifier cookie for OAuth callback\",\n });\n resCookies.push(clearCookie(\"pkce\", providerId));\n }\n\n let nonce: string | undefined;\n if (oauthConfig.nonce === true) {\n const nonceCookieName = oauthCookieName(\"nonce\", providerId);\n nonce = yield* cookies[nonceCookieName] != null\n ? Fx.succeed(cookies[nonceCookieName]!)\n : Cv.fail({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: \"Missing nonce cookie for OAuth callback\",\n });\n resCookies.push(clearCookie(\"nonce\", providerId));\n }\n\n // 4. Exchange code for tokens\n const tokens = yield* exchangeCode(arcticProvider, code, codeVerifier);\n\n if (oauthConfig.validateTokens !== undefined) {\n yield* Fx.from({\n ok: () => oauthConfig.validateTokens!(tokens, { nonce }),\n err: (e) =>\n Cv.error({\n code: \"OAUTH_PROVIDER_ERROR\",\n message: `Token validation failed: ${e instanceof Error ? e.message : String(e)}`,\n }),\n });\n }\n\n // 5. Extract profile\n const rawProfile = yield* extractProfile(providerId, oauthConfig, tokens);\n const profile = yield* validateProfileId(providerId, rawProfile);\n\n logWithLevel(\"DEBUG\", \"OAuth callback profile extracted\", {\n providerId,\n profileId: profile.id,\n });\n\n // 6. Compute signature for verifier validation\n const state = storedState!;\n const signature = getAuthorizationSignature({ codeVerifier, state });\n\n return {\n profile,\n providerAccountId: profile.id,\n cookies: resCookies,\n signature,\n };\n });\n}\n"],"mappings":"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"}
|
package/dist/server/passkey.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { AuthDataModel, GenericActionCtxWithAuthConfig, PasskeyProviderConfig, SessionInfo } from "./types.js";
|
|
2
|
-
import { Fx } from "@robelest/fx";
|
|
3
|
-
import { ConvexError } from "convex/values";
|
|
4
|
-
|
|
5
|
-
//#region src/server/passkey.d.ts
|
|
6
|
-
type EnrichedActionCtx = GenericActionCtxWithAuthConfig<AuthDataModel>;
|
|
7
|
-
/** Result type for all passkey flows. */
|
|
8
|
-
type PasskeyResult = {
|
|
9
|
-
kind: "signedIn";
|
|
10
|
-
signedIn: SessionInfo | null;
|
|
11
|
-
} | {
|
|
12
|
-
kind: "passkeyOptions";
|
|
13
|
-
options: Record<string, any>;
|
|
14
|
-
verifier: string;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Main passkey handler dispatched from signIn.ts.
|
|
18
|
-
*
|
|
19
|
-
* Routes to the appropriate phase based on `params.flow` via `dispatchFx`.
|
|
20
|
-
*/
|
|
21
|
-
declare function handlePasskeyFx(ctx: EnrichedActionCtx, provider: PasskeyProviderConfig, args: {
|
|
22
|
-
params?: Record<string, any>;
|
|
23
|
-
verifier?: string;
|
|
24
|
-
}): Fx<PasskeyResult, ConvexError<any>>;
|
|
25
|
-
//#endregion
|
|
26
|
-
export { handlePasskeyFx };
|
|
27
|
-
//# sourceMappingURL=passkey.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"passkey.d.ts","names":[],"sources":["../../src/server/passkey.ts"],"mappings":";;;;;KAoEK,iBAAA,GAAoB,8BAAA,CAA+B,aAAA;;KAwLnD,aAAA;EACC,IAAA;EAAkB,QAAA,EAAU,WAAA;AAAA;EAC5B,IAAA;EAAwB,OAAA,EAAS,MAAA;EAAqB,QAAA;AAAA;;;;;;iBAkD5C,eAAA,CACd,GAAA,EAAK,iBAAA,EACL,QAAA,EAAU,qBAAA,EACV,IAAA;EACE,MAAA,GAAS,MAAA;EACT,QAAA;AAAA,IAED,EAAA,CAAO,aAAA,EAAe,WAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"passkey.js","names":["hasSiteUrl","hasRpId","siteUrl"],"sources":["../../src/server/passkey.ts"],"sourcesContent":["/**\n * Server-side WebAuthn ceremony logic for passkey authentication.\n *\n * Handles the four phases of the WebAuthn flow:\n * 1. registerOptions — generate PublicKeyCredentialCreationOptions\n * 2. registerVerify — verify attestation and store credential\n * 3. authOptions — generate PublicKeyCredentialRequestOptions\n * 4. authVerify — verify assertion signature and sign in\n *\n * Uses `@oslojs/webauthn` for attestation/assertion parsing and\n * `@oslojs/crypto` for signature verification.\n *\n * All functions return `Fx<A, ConvexError<any>>` composed via `Fx.chain` pipelines.\n *\n * @module\n */\n\nimport {\n p256,\n verifyECDSASignature,\n decodeSEC1PublicKey,\n decodePKIXECDSASignature,\n} from \"@oslojs/crypto/ecdsa\";\nimport {\n RSAPublicKey,\n decodePKCS1RSAPublicKey,\n sha256ObjectIdentifier,\n verifyRSASSAPKCS1v15Signature,\n} from \"@oslojs/crypto/rsa\";\nimport { sha256 } from \"@oslojs/crypto/sha2\";\nimport {\n encodeBase64urlNoPadding,\n decodeBase64urlIgnorePadding,\n} from \"@oslojs/encoding\";\nimport {\n parseAttestationObject,\n parseClientDataJSON,\n parseAuthenticatorData,\n createAssertionSignatureMessage,\n ClientDataType,\n coseAlgorithmES256,\n coseAlgorithmRS256,\n COSEKeyType,\n} from \"@oslojs/webauthn\";\nimport type { Fx as FxType } from \"@robelest/fx\";\nimport { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport type { ConvexError } from \"convex/values\";\n\nimport { authDb } from \"./db\";\nimport { userIdFromIdentitySubject } from \"./identity\";\nimport { callSignIn, callVerifier } from \"./mutations/index\";\nimport { callVerifierSignature } from \"./mutations/signature\";\nimport { PasskeyProviderConfig, GenericActionCtxWithAuthConfig } from \"./types\";\nimport {\n AuthDataModel,\n SessionInfo,\n queryUserById,\n queryUserByVerifiedEmail,\n queryPasskeysByUserId,\n queryPasskeyByCredentialId,\n queryVerifierById,\n mutatePasskeyInsert,\n mutatePasskeyUpdateCounter,\n mutateVerifierDelete,\n} from \"./types\";\nimport { siteUrlsFromEnv } from \"./utils\";\n\ntype EnrichedActionCtx = GenericActionCtxWithAuthConfig<AuthDataModel>;\n\n// ============================================================================\n// Resolve RP options — Fx pipeline with validation\n// ============================================================================\n\n/** Resolved relying party configuration. */\ninterface RpOptions {\n rpName: string;\n rpId: string;\n origin: string | string[];\n attestation: string;\n userVerification: string;\n residentKey: string;\n authenticatorAttachment?: string;\n algorithms: number[];\n challengeExpirationMs: number;\n}\n\n/**\n * Resolve passkey relying party options from provider config and environment.\n *\n * Returns `Fx<RpOptions, ConvexError<any>>` — fails if neither SITE_URL nor rpId\n * is configured.\n */\nconst resolveRpOptionsFx = (\n provider: PasskeyProviderConfig,\n): FxType<RpOptions, ConvexError<any>> => {\n const configuredSiteUrls =\n process.env.SITE_URL === undefined ? null : siteUrlsFromEnv();\n const siteUrl = configuredSiteUrls?.primaryUrl;\n const hasSiteUrl = siteUrl !== undefined && siteUrl !== \"\";\n const hasRpId = provider.options.rpId !== undefined;\n\n return Fx.succeed({ siteUrl, hasSiteUrl, hasRpId }).pipe(\n Fx.chain(({ siteUrl, hasSiteUrl, hasRpId }) =>\n !hasSiteUrl && !hasRpId\n ? Cv.fail({\n code: \"PASSKEY_MISSING_CONFIG\",\n message:\n \"Passkey provider requires SITE_URL env var (your frontend URL) \" +\n \"or explicit rpId / origin in the provider config. \" +\n \"CONVEX_SITE_URL cannot be used because WebAuthn RP ID must match the frontend domain.\",\n })\n : Fx.succeed(siteUrl),\n ),\n Fx.map((siteUrl) => {\n const siteHostname = siteUrl ? new URL(siteUrl).hostname : undefined;\n const defaultOrigin = configuredSiteUrls?.allowedUrls ?? siteUrl;\n return {\n rpName: provider.options.rpName ?? siteHostname ?? \"localhost\",\n rpId: provider.options.rpId ?? siteHostname ?? \"localhost\",\n origin: provider.options.origin ?? defaultOrigin ?? \"http://localhost\",\n attestation: provider.options.attestation ?? \"none\",\n userVerification: provider.options.userVerification ?? \"required\",\n residentKey: provider.options.residentKey ?? \"preferred\",\n authenticatorAttachment: provider.options.authenticatorAttachment,\n algorithms: provider.options.algorithms ?? [\n coseAlgorithmES256,\n coseAlgorithmRS256,\n ],\n challengeExpirationMs:\n provider.options.challengeExpirationMs ?? 300_000,\n };\n }),\n );\n};\n\n// ============================================================================\n// Composable validators — small functions (A) => Fx<B, ConvexError<any>>\n// ============================================================================\n\n/** Verify client data type matches expected WebAuthn ceremony type. */\nconst verifyClientDataType =\n <T extends { type: ClientDataType }>(\n expectedType: ClientDataType,\n label: string,\n ) =>\n (clientData: T): FxType<T, ConvexError<any>> =>\n clientData.type === expectedType\n ? Fx.succeed(clientData)\n : Cv.fail({\n code: \"PASSKEY_INVALID_CLIENT_DATA\",\n message: `Invalid client data type: expected ${label}`,\n });\n\n/** Verify origin is in the allowed list. */\nconst verifyOrigin =\n (rp: RpOptions) =>\n <T extends { origin: string }>(\n clientData: T,\n ): FxType<T, ConvexError<any>> => {\n const allowed = Array.isArray(rp.origin) ? rp.origin : [rp.origin];\n return allowed.includes(clientData.origin)\n ? Fx.succeed(clientData)\n : Cv.fail({\n code: \"PASSKEY_INVALID_ORIGIN\",\n message: `Invalid origin: ${clientData.origin}, expected one of: ${allowed.join(\", \")}`,\n });\n };\n\n/** Verify the challenge hash matches the stored verifier, then delete verifier. */\nconst verifyAndConsumeChallenge =\n (ctx: EnrichedActionCtx, verifierValue: string) =>\n <T extends { challenge: Uint8Array }>(\n clientData: T,\n ): FxType<T, ConvexError<any>> => {\n const challengeHash = encodeBase64urlNoPadding(\n new Uint8Array(sha256(clientData.challenge)),\n );\n return Fx.from({\n ok: () => queryVerifierById(ctx, verifierValue),\n err: () =>\n Cv.error({\n code: \"PASSKEY_INVALID_CHALLENGE\",\n message: \"Invalid or expired passkey challenge.\",\n }),\n }).pipe(\n Fx.chain((doc) =>\n !doc || doc.signature !== challengeHash\n ? Cv.fail({\n code: \"PASSKEY_INVALID_CHALLENGE\",\n message: \"Invalid or expired passkey challenge.\",\n })\n : Fx.succeed(doc),\n ),\n Fx.chain(() =>\n Fx.from({\n ok: () => mutateVerifierDelete(ctx, verifierValue),\n err: () =>\n Cv.error({\n code: \"PASSKEY_INVALID_CHALLENGE\",\n message: \"Invalid or expired passkey challenge.\",\n }),\n }),\n ),\n Fx.map(() => clientData),\n );\n };\n\n/** Verify RP ID hash matches. */\nconst verifyRpId =\n (rpId: string) =>\n <T extends { verifyRelyingPartyIdHash: (id: string) => boolean }>(\n authData: T,\n ): FxType<T, ConvexError<any>> =>\n authData.verifyRelyingPartyIdHash(rpId)\n ? Fx.succeed(authData)\n : Cv.fail({\n code: \"PASSKEY_RP_MISMATCH\",\n message: \"Relying party ID mismatch.\",\n });\n\n/** Verify user presence and (optionally) user verification flags. */\nconst verifyUserFlags =\n (rp: RpOptions) =>\n <T extends { userPresent: boolean; userVerified: boolean }>(\n authData: T,\n ): FxType<T, ConvexError<any>> =>\n !authData.userPresent\n ? Cv.fail({\n code: \"PASSKEY_USER_PRESENCE\",\n message: \"User presence flag not set.\",\n })\n : rp.userVerification === \"required\" && !authData.userVerified\n ? Cv.fail({\n code: \"PASSKEY_USER_VERIFICATION\",\n message: \"User verification required but not performed.\",\n })\n : Fx.succeed(authData);\n\n// ============================================================================\n// Registration flow\n// ============================================================================\n\n// ============================================================================\n// Authentication flow\n// ============================================================================\n\n// ============================================================================\n// Main dispatch\n// ============================================================================\n\n/** Result type for all passkey flows. */\ntype PasskeyResult =\n | { kind: \"signedIn\"; signedIn: SessionInfo | null }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string };\n\nconst PASSKEY_FLOW = {\n registerOptions: \"registerOptions\",\n registerVerify: \"registerVerify\",\n authOptions: \"authOptions\",\n authVerify: \"authVerify\",\n} as const;\n\nconst PASSKEY_FLOWS = [\n PASSKEY_FLOW.registerOptions,\n PASSKEY_FLOW.registerVerify,\n PASSKEY_FLOW.authOptions,\n PASSKEY_FLOW.authVerify,\n] as const;\n\ntype PasskeyDispatch =\n | { flow: typeof PASSKEY_FLOW.registerOptions }\n | { flow: typeof PASSKEY_FLOW.registerVerify }\n | { flow: typeof PASSKEY_FLOW.authOptions }\n | { flow: typeof PASSKEY_FLOW.authVerify };\n\nconst resolvePasskeyDispatchFx = (\n params: Record<string, unknown>,\n): FxType<PasskeyDispatch, ConvexError<any>> => {\n const flow = params.flow;\n return typeof flow === \"string\" && PASSKEY_FLOWS.includes(flow as never)\n ? Fx.succeed({ flow: flow as (typeof PASSKEY_FLOWS)[number] })\n : Cv.fail({\n code: \"PASSKEY_MISSING_FLOW\",\n message:\n \"Missing `flow` parameter. Expected one of: registerOptions, registerVerify, authOptions, authVerify\",\n });\n};\n\nconst requirePasskeyVerifierFx = (\n verifier: string | undefined,\n): FxType<string, ConvexError<any>> =>\n verifier != null\n ? Fx.succeed(verifier)\n : Cv.fail({\n code: \"PASSKEY_MISSING_VERIFIER\",\n message: \"Missing verifier for passkey operation.\",\n });\n\n/**\n * Main passkey handler dispatched from signIn.ts.\n *\n * Routes to the appropriate phase based on `params.flow` via `dispatchFx`.\n */\nexport function handlePasskeyFx(\n ctx: EnrichedActionCtx,\n provider: PasskeyProviderConfig,\n args: {\n params?: Record<string, any>;\n verifier?: string;\n },\n): FxType<PasskeyResult, ConvexError<any>> {\n const params = (args.params ?? {}) as Record<string, any>;\n\n return resolvePasskeyDispatchFx(params).pipe(\n Fx.chain((dispatch) => {\n const flowFx: FxType<PasskeyResult, ConvexError<any>> = Fx.match(\n dispatch,\n ).on(\"flow\", {\n registerOptions: (_) =>\n Fx.zip(\n Fx.from({\n ok: () => ctx.auth.getUserIdentity(),\n err: () =>\n Cv.error({\n code: \"PASSKEY_AUTH_REQUIRED\",\n message: \"Sign in first, then add a passkey to your account.\",\n }),\n }).pipe(\n Fx.chain((id) =>\n id === null\n ? Cv.fail({\n code: \"PASSKEY_AUTH_REQUIRED\",\n message:\n \"Sign in first, then add a passkey to your account.\",\n })\n : Fx.succeed(userIdFromIdentitySubject(id.subject)),\n ),\n ),\n resolveRpOptionsFx(provider),\n ).pipe(\n Fx.chain(([userId, rp]) => {\n const challenge = new Uint8Array(32);\n crypto.getRandomValues(challenge);\n const challengeHash = encodeBase64urlNoPadding(\n new Uint8Array(sha256(challenge)),\n );\n\n return Fx.from({\n ok: async () => {\n const verifier = await callVerifier(ctx);\n await callVerifierSignature(ctx, {\n verifier,\n signature: challengeHash,\n });\n\n const user = await queryUserById(ctx, userId);\n const userName = params.userName ?? user?.email ?? \"user\";\n const userDisplayName =\n params.userDisplayName ?? user?.name ?? userName;\n\n const existing = await queryPasskeysByUserId(ctx, userId);\n const excludeCredentials = existing.map((pk) => ({\n id: pk.credentialId,\n transports: pk.transports,\n }));\n\n const userHandle = encodeBase64urlNoPadding(\n new TextEncoder().encode(userId),\n );\n\n const options = {\n rp: { name: rp.rpName, id: rp.rpId },\n user: {\n id: userHandle,\n name: userName,\n displayName: userDisplayName,\n },\n challenge: encodeBase64urlNoPadding(challenge),\n pubKeyCredParams: rp.algorithms.map((alg) => ({\n type: \"public-key\" as const,\n alg,\n })),\n timeout: rp.challengeExpirationMs,\n attestation: rp.attestation,\n authenticatorSelection: {\n residentKey: rp.residentKey,\n requireResidentKey: rp.residentKey === \"required\",\n userVerification: rp.userVerification,\n ...(rp.authenticatorAttachment\n ? {\n authenticatorAttachment: rp.authenticatorAttachment,\n }\n : {}),\n },\n excludeCredentials,\n };\n\n return {\n kind: \"passkeyOptions\" as const,\n options,\n verifier,\n };\n },\n err: () =>\n Cv.error({\n code: \"INTERNAL_ERROR\",\n message: \"An unexpected error occurred.\",\n }),\n });\n }),\n ),\n registerVerify: (_) =>\n Fx.zip(\n Fx.from({\n ok: () => ctx.auth.getUserIdentity(),\n err: () =>\n Cv.error({\n code: \"PASSKEY_AUTH_REQUIRED\",\n message: \"Sign in first, then add a passkey to your account.\",\n }),\n }).pipe(\n Fx.chain((id) =>\n id === null\n ? Cv.fail({\n code: \"PASSKEY_AUTH_REQUIRED\",\n message:\n \"Sign in first, then add a passkey to your account.\",\n })\n : Fx.succeed(userIdFromIdentitySubject(id.subject)),\n ),\n ),\n resolveRpOptionsFx(provider),\n ).pipe(\n Fx.chain(([userId, rp]) =>\n requirePasskeyVerifierFx(args.verifier).pipe(\n Fx.chain((verifier) => {\n const clientDataJSON = decodeBase64urlIgnorePadding(\n params.clientDataJSON,\n );\n const clientData = parseClientDataJSON(clientDataJSON);\n\n const verifiedClientDataFx = Fx.succeed(clientData).pipe(\n Fx.chain(\n verifyClientDataType(\n ClientDataType.Create,\n \"webauthn.create\",\n ),\n ),\n Fx.chain(verifyOrigin(rp)),\n Fx.chain(verifyAndConsumeChallenge(ctx, verifier)),\n Fx.map(() => {\n const attestationObjectBytes =\n decodeBase64urlIgnorePadding(params.attestationObject);\n const attestation = parseAttestationObject(\n attestationObjectBytes,\n );\n return attestation.authenticatorData;\n }),\n );\n\n return verifiedClientDataFx.pipe(\n Fx.chain(verifyRpId(rp.rpId)),\n Fx.chain(verifyUserFlags(rp)),\n Fx.chain((authData) => {\n if (authData.credential == null) {\n return Cv.fail({\n code: \"PASSKEY_NO_CREDENTIAL\",\n message: \"No credential in attestation.\",\n });\n }\n return Fx.succeed({\n authData,\n credential: authData.credential,\n });\n }),\n Fx.chain(({ authData, credential }) => {\n const credentialId = encodeBase64urlNoPadding(\n credential.id,\n );\n const publicKey = credential.publicKey;\n\n let algorithm: number;\n if (publicKey.isAlgorithmDefined()) {\n algorithm = publicKey.algorithm();\n } else {\n const keyType = publicKey.type();\n algorithm =\n keyType === COSEKeyType.EC2\n ? coseAlgorithmES256\n : keyType === COSEKeyType.RSA\n ? coseAlgorithmRS256\n : coseAlgorithmES256;\n }\n\n const handlers: Record<\n number,\n (() => FxType<Uint8Array, ConvexError<any>>) | undefined\n > = {\n [coseAlgorithmES256]: () => {\n const ec2 = publicKey.ec2();\n const xBytes = new Uint8Array(32);\n let vx = ec2.x;\n for (let i = 31; i >= 0; i--) {\n xBytes[i] = Number(vx & 0xffn);\n vx >>= 8n;\n }\n const yBytes = new Uint8Array(32);\n let vy = ec2.y;\n for (let i = 31; i >= 0; i--) {\n yBytes[i] = Number(vy & 0xffn);\n vy >>= 8n;\n }\n const bytes = new Uint8Array(65);\n bytes[0] = 0x04;\n bytes.set(xBytes, 1);\n bytes.set(yBytes, 33);\n return Fx.succeed(bytes);\n },\n [coseAlgorithmRS256]: () => {\n const rsa = publicKey.rsa();\n const rsaPubKey = new RSAPublicKey(rsa.n, rsa.e);\n return Fx.succeed(rsaPubKey.encodePKCS1());\n },\n };\n\n const handler = handlers[algorithm];\n return (\n handler\n ? handler()\n : Cv.fail({\n code: \"PASSKEY_UNSUPPORTED_ALGORITHM\",\n message: `Unsupported algorithm: ${algorithm}`,\n })\n ).pipe(\n Fx.chain((publicKeyBytes) =>\n Fx.from({\n ok: async () => {\n const deviceType =\n params.deviceType ?? \"single-device\";\n const backedUp = params.backedUp ?? false;\n\n const db = authDb(ctx, ctx.auth.config);\n await db.accounts.create({\n userId,\n provider: provider.id,\n providerAccountId: credentialId,\n });\n\n await mutatePasskeyInsert(ctx, {\n userId,\n credentialId,\n publicKey: publicKeyBytes.buffer.slice(\n publicKeyBytes.byteOffset,\n publicKeyBytes.byteOffset +\n publicKeyBytes.byteLength,\n ),\n algorithm,\n counter: authData.signatureCounter,\n transports: params.transports,\n deviceType,\n backedUp,\n name: params.passkeyName,\n createdAt: Date.now(),\n });\n\n const signInResult = await callSignIn(ctx, {\n userId,\n generateTokens: true,\n });\n\n return {\n kind: \"signedIn\" as const,\n signedIn: signInResult,\n };\n },\n err: () =>\n Cv.error({\n code: \"INTERNAL_ERROR\",\n message: \"An unexpected error occurred.\",\n }),\n }),\n ),\n );\n }),\n );\n }),\n ),\n ),\n ),\n authOptions: (_) =>\n resolveRpOptionsFx(provider).pipe(\n Fx.chain((rp) => {\n const challenge = new Uint8Array(32);\n crypto.getRandomValues(challenge);\n const challengeHash = encodeBase64urlNoPadding(\n new Uint8Array(sha256(challenge)),\n );\n\n return Fx.from({\n ok: async () => {\n const verifier = await callVerifier(ctx);\n await callVerifierSignature(ctx, {\n verifier,\n signature: challengeHash,\n });\n\n let allowCredentials:\n | Array<{\n type: string;\n id: string;\n transports?: string[];\n }>\n | undefined;\n if (params.email) {\n const user = await queryUserByVerifiedEmail(\n ctx,\n params.email,\n );\n if (user) {\n const passkeys = await queryPasskeysByUserId(\n ctx,\n user._id,\n );\n if (passkeys.length > 0) {\n allowCredentials = passkeys.map((pk) => ({\n type: \"public-key\",\n id: pk.credentialId,\n transports: pk.transports,\n }));\n }\n }\n }\n\n const options: Record<string, any> = {\n challenge: encodeBase64urlNoPadding(challenge),\n timeout: rp.challengeExpirationMs,\n rpId: rp.rpId,\n userVerification: rp.userVerification,\n };\n\n if (allowCredentials) {\n options.allowCredentials = allowCredentials;\n }\n\n return {\n kind: \"passkeyOptions\" as const,\n options,\n verifier,\n };\n },\n err: () =>\n Cv.error({\n code: \"INTERNAL_ERROR\",\n message: \"An unexpected error occurred.\",\n }),\n });\n }),\n ),\n authVerify: (_) =>\n Fx.zip(\n resolveRpOptionsFx(provider),\n requirePasskeyVerifierFx(args.verifier),\n ).pipe(\n Fx.chain(([rp, verifier]) => {\n const clientDataJSON = decodeBase64urlIgnorePadding(\n params.clientDataJSON,\n );\n const clientData = parseClientDataJSON(clientDataJSON);\n\n const verifiedClientDataFx = Fx.succeed(clientData).pipe(\n Fx.chain(\n verifyClientDataType(ClientDataType.Get, \"webauthn.get\"),\n ),\n Fx.chain(verifyOrigin(rp)),\n Fx.chain(verifyAndConsumeChallenge(ctx, verifier)),\n Fx.chain(() =>\n params.credentialId != null\n ? Fx.succeed(params.credentialId as string)\n : Cv.fail({\n code: \"PASSKEY_UNKNOWN_CREDENTIAL\",\n message: \"Missing credential ID\",\n }),\n ),\n );\n\n return verifiedClientDataFx.pipe(\n Fx.chain((credentialId) =>\n Fx.from({\n ok: () => queryPasskeyByCredentialId(ctx, credentialId),\n err: () =>\n Cv.error({\n code: \"PASSKEY_UNKNOWN_CREDENTIAL\",\n message: \"Unknown passkey credential.\",\n }),\n }).pipe(\n Fx.chain((passkey) =>\n passkey\n ? Fx.succeed(passkey)\n : Cv.fail({\n code: \"PASSKEY_UNKNOWN_CREDENTIAL\",\n message: \"Unknown credential\",\n }),\n ),\n ),\n ),\n Fx.chain((passkey) => {\n const authenticatorDataBytes = decodeBase64urlIgnorePadding(\n params.authenticatorData,\n );\n const authenticatorData = parseAuthenticatorData(\n authenticatorDataBytes,\n );\n\n const signature = decodeBase64urlIgnorePadding(\n params.signature,\n );\n const signatureMessage = createAssertionSignatureMessage(\n authenticatorDataBytes,\n clientDataJSON,\n );\n const messageHash = sha256(signatureMessage);\n\n const checkedAuthenticatorFx = Fx.succeed(\n authenticatorData,\n ).pipe(\n Fx.chain(verifyRpId(rp.rpId)),\n Fx.chain(verifyUserFlags(rp)),\n );\n\n const signatureVerifiedFx = checkedAuthenticatorFx.pipe(\n Fx.chain(() => {\n const storedPublicKeyBytes = new Uint8Array(\n passkey.publicKey,\n );\n const algorithmHandlers: Record<\n number,\n (() => FxType<void, ConvexError<any>>) | undefined\n > = {\n [coseAlgorithmES256]: () => {\n const ecPublicKey = decodeSEC1PublicKey(\n p256,\n storedPublicKeyBytes,\n );\n const ecdsaSignature =\n decodePKIXECDSASignature(signature);\n const valid = verifyECDSASignature(\n ecPublicKey,\n messageHash,\n ecdsaSignature,\n );\n return valid\n ? Fx.succeed(undefined as void)\n : Cv.fail({\n code: \"PASSKEY_INVALID_SIGNATURE\",\n message: \"Invalid passkey signature.\",\n });\n },\n [coseAlgorithmRS256]: () => {\n const rsaPublicKey =\n decodePKCS1RSAPublicKey(storedPublicKeyBytes);\n const valid = verifyRSASSAPKCS1v15Signature(\n rsaPublicKey,\n sha256ObjectIdentifier,\n messageHash,\n signature,\n );\n return valid\n ? Fx.succeed(undefined as void)\n : Cv.fail({\n code: \"PASSKEY_INVALID_SIGNATURE\",\n message: \"Invalid passkey signature.\",\n });\n },\n };\n\n const handler = algorithmHandlers[passkey.algorithm];\n return handler\n ? handler()\n : Cv.fail({\n code: \"PASSKEY_UNSUPPORTED_ALGORITHM\",\n message: `Unsupported algorithm: ${passkey.algorithm}`,\n });\n }),\n );\n\n const counterValidatedFx = signatureVerifiedFx.pipe(\n Fx.chain(() =>\n passkey.counter !== 0 &&\n authenticatorData.signatureCounter !== 0 &&\n authenticatorData.signatureCounter <= passkey.counter\n ? Cv.fail({\n code: \"PASSKEY_COUNTER_ERROR\",\n message:\n \"Authenticator counter did not increase — possible credential cloning detected.\",\n })\n : Fx.succeed(authenticatorData),\n ),\n );\n\n return counterValidatedFx.pipe(\n Fx.chain(() =>\n Fx.from({\n ok: async () => {\n await mutatePasskeyUpdateCounter(\n ctx,\n passkey._id,\n authenticatorData.signatureCounter,\n Date.now(),\n );\n\n const signInResult = await callSignIn(ctx, {\n userId: passkey.userId,\n generateTokens: true,\n });\n\n return {\n kind: \"signedIn\" as const,\n signedIn: signInResult,\n };\n },\n err: () =>\n Cv.error({\n code: \"INTERNAL_ERROR\",\n message: \"An unexpected error occurred.\",\n }),\n }),\n ),\n );\n }),\n );\n }),\n ),\n });\n return flowFx;\n }),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6FA,MAAM,sBACJ,aACwC;CACxC,MAAM,qBACJ,QAAQ,IAAI,aAAa,SAAY,OAAO,iBAAiB;CAC/D,MAAM,UAAU,oBAAoB;CACpC,MAAM,aAAa,YAAY,UAAa,YAAY;CACxD,MAAM,UAAU,SAAS,QAAQ,SAAS;AAE1C,QAAO,GAAG,QAAQ;EAAE;EAAS;EAAY;EAAS,CAAC,CAAC,KAClD,GAAG,OAAO,EAAE,oBAAS,0BAAY,yBAC/B,CAACA,gBAAc,CAACC,YACZ,GAAG,KAAK;EACN,MAAM;EACN,SACE;EAGH,CAAC,GACF,GAAG,QAAQC,UAAQ,CACxB,EACD,GAAG,KAAK,cAAY;EAClB,MAAM,eAAeA,YAAU,IAAI,IAAIA,UAAQ,CAAC,WAAW;EAC3D,MAAM,gBAAgB,oBAAoB,eAAeA;AACzD,SAAO;GACL,QAAQ,SAAS,QAAQ,UAAU,gBAAgB;GACnD,MAAM,SAAS,QAAQ,QAAQ,gBAAgB;GAC/C,QAAQ,SAAS,QAAQ,UAAU,iBAAiB;GACpD,aAAa,SAAS,QAAQ,eAAe;GAC7C,kBAAkB,SAAS,QAAQ,oBAAoB;GACvD,aAAa,SAAS,QAAQ,eAAe;GAC7C,yBAAyB,SAAS,QAAQ;GAC1C,YAAY,SAAS,QAAQ,cAAc,CACzC,oBACA,mBACD;GACD,uBACE,SAAS,QAAQ,yBAAyB;GAC7C;GACD,CACH;;;AAQH,MAAM,wBAEF,cACA,WAED,eACC,WAAW,SAAS,eAChB,GAAG,QAAQ,WAAW,GACtB,GAAG,KAAK;CACN,MAAM;CACN,SAAS,sCAAsC;CAChD,CAAC;;AAGV,MAAM,gBACH,QAEC,eACgC;CAChC,MAAM,UAAU,MAAM,QAAQ,GAAG,OAAO,GAAG,GAAG,SAAS,CAAC,GAAG,OAAO;AAClE,QAAO,QAAQ,SAAS,WAAW,OAAO,GACtC,GAAG,QAAQ,WAAW,GACtB,GAAG,KAAK;EACN,MAAM;EACN,SAAS,mBAAmB,WAAW,OAAO,qBAAqB,QAAQ,KAAK,KAAK;EACtF,CAAC;;;AAIV,MAAM,6BACH,KAAwB,mBAEvB,eACgC;CAChC,MAAM,gBAAgB,yBACpB,IAAI,WAAW,OAAO,WAAW,UAAU,CAAC,CAC7C;AACD,QAAO,GAAG,KAAK;EACb,UAAU,kBAAkB,KAAK,cAAc;EAC/C,WACE,GAAG,MAAM;GACP,MAAM;GACN,SAAS;GACV,CAAC;EACL,CAAC,CAAC,KACD,GAAG,OAAO,QACR,CAAC,OAAO,IAAI,cAAc,gBACtB,GAAG,KAAK;EACN,MAAM;EACN,SAAS;EACV,CAAC,GACF,GAAG,QAAQ,IAAI,CACpB,EACD,GAAG,YACD,GAAG,KAAK;EACN,UAAU,qBAAqB,KAAK,cAAc;EAClD,WACE,GAAG,MAAM;GACP,MAAM;GACN,SAAS;GACV,CAAC;EACL,CAAC,CACH,EACD,GAAG,UAAU,WAAW,CACzB;;;AAIL,MAAM,cACH,UAEC,aAEA,SAAS,yBAAyB,KAAK,GACnC,GAAG,QAAQ,SAAS,GACpB,GAAG,KAAK;CACN,MAAM;CACN,SAAS;CACV,CAAC;;AAGV,MAAM,mBACH,QAEC,aAEA,CAAC,SAAS,cACN,GAAG,KAAK;CACN,MAAM;CACN,SAAS;CACV,CAAC,GACF,GAAG,qBAAqB,cAAc,CAAC,SAAS,eAC9C,GAAG,KAAK;CACN,MAAM;CACN,SAAS;CACV,CAAC,GACF,GAAG,QAAQ,SAAS;AAmB9B,MAAM,eAAe;CACnB,iBAAiB;CACjB,gBAAgB;CAChB,aAAa;CACb,YAAY;CACb;AAED,MAAM,gBAAgB;CACpB,aAAa;CACb,aAAa;CACb,aAAa;CACb,aAAa;CACd;AAQD,MAAM,4BACJ,WAC8C;CAC9C,MAAM,OAAO,OAAO;AACpB,QAAO,OAAO,SAAS,YAAY,cAAc,SAAS,KAAc,GACpE,GAAG,QAAQ,EAAQ,MAAwC,CAAC,GAC5D,GAAG,KAAK;EACN,MAAM;EACN,SACE;EACH,CAAC;;AAGR,MAAM,4BACJ,aAEA,YAAY,OACR,GAAG,QAAQ,SAAS,GACpB,GAAG,KAAK;CACN,MAAM;CACN,SAAS;CACV,CAAC;;;;;;AAOR,SAAgB,gBACd,KACA,UACA,MAIyC;CACzC,MAAM,SAAU,KAAK,UAAU,EAAE;AAEjC,QAAO,yBAAyB,OAAO,CAAC,KACtC,GAAG,OAAO,aAAa;AAugBrB,SAtgBwD,GAAG,MACzD,SACD,CAAC,GAAG,QAAQ;GACX,kBAAkB,MAChB,GAAG,IACD,GAAG,KAAK;IACN,UAAU,IAAI,KAAK,iBAAiB;IACpC,WACE,GAAG,MAAM;KACP,MAAM;KACN,SAAS;KACV,CAAC;IACL,CAAC,CAAC,KACD,GAAG,OAAO,OACR,OAAO,OACH,GAAG,KAAK;IACN,MAAM;IACN,SACE;IACH,CAAC,GACF,GAAG,QAAQ,0BAA0B,GAAG,QAAQ,CAAC,CACtD,CACF,EACD,mBAAmB,SAAS,CAC7B,CAAC,KACA,GAAG,OAAO,CAAC,QAAQ,QAAQ;IACzB,MAAM,YAAY,IAAI,WAAW,GAAG;AACpC,WAAO,gBAAgB,UAAU;IACjC,MAAM,gBAAgB,yBACpB,IAAI,WAAW,OAAO,UAAU,CAAC,CAClC;AAED,WAAO,GAAG,KAAK;KACb,IAAI,YAAY;MACd,MAAM,WAAW,MAAM,aAAa,IAAI;AACxC,YAAM,sBAAsB,KAAK;OAC/B;OACA,WAAW;OACZ,CAAC;MAEF,MAAM,OAAO,MAAM,cAAc,KAAK,OAAO;MAC7C,MAAM,WAAW,OAAO,YAAY,MAAM,SAAS;MACnD,MAAM,kBACJ,OAAO,mBAAmB,MAAM,QAAQ;MAG1C,MAAM,sBADW,MAAM,sBAAsB,KAAK,OAAO,EACrB,KAAK,QAAQ;OAC/C,IAAI,GAAG;OACP,YAAY,GAAG;OAChB,EAAE;MAEH,MAAM,aAAa,yBACjB,IAAI,aAAa,CAAC,OAAO,OAAO,CACjC;AA6BD,aAAO;OACL,MAAM;OACN,SA7Bc;QACd,IAAI;SAAE,MAAM,GAAG;SAAQ,IAAI,GAAG;SAAM;QACpC,MAAM;SACJ,IAAI;SACJ,MAAM;SACN,aAAa;SACd;QACD,WAAW,yBAAyB,UAAU;QAC9C,kBAAkB,GAAG,WAAW,KAAK,SAAS;SAC5C,MAAM;SACN;SACD,EAAE;QACH,SAAS,GAAG;QACZ,aAAa,GAAG;QAChB,wBAAwB;SACtB,aAAa,GAAG;SAChB,oBAAoB,GAAG,gBAAgB;SACvC,kBAAkB,GAAG;SACrB,GAAI,GAAG,0BACH,EACE,yBAAyB,GAAG,yBAC7B,GACD,EAAE;SACP;QACD;QACD;OAKC;OACD;;KAEH,WACE,GAAG,MAAM;MACP,MAAM;MACN,SAAS;MACV,CAAC;KACL,CAAC;KACF,CACH;GACH,iBAAiB,MACf,GAAG,IACD,GAAG,KAAK;IACN,UAAU,IAAI,KAAK,iBAAiB;IACpC,WACE,GAAG,MAAM;KACP,MAAM;KACN,SAAS;KACV,CAAC;IACL,CAAC,CAAC,KACD,GAAG,OAAO,OACR,OAAO,OACH,GAAG,KAAK;IACN,MAAM;IACN,SACE;IACH,CAAC,GACF,GAAG,QAAQ,0BAA0B,GAAG,QAAQ,CAAC,CACtD,CACF,EACD,mBAAmB,SAAS,CAC7B,CAAC,KACA,GAAG,OAAO,CAAC,QAAQ,QACjB,yBAAyB,KAAK,SAAS,CAAC,KACtC,GAAG,OAAO,aAAa;IAIrB,MAAM,aAAa,oBAHI,6BACrB,OAAO,eACR,CACqD;AAqBtD,WAnB6B,GAAG,QAAQ,WAAW,CAAC,KAClD,GAAG,MACD,qBACE,eAAe,QACf,kBACD,CACF,EACD,GAAG,MAAM,aAAa,GAAG,CAAC,EAC1B,GAAG,MAAM,0BAA0B,KAAK,SAAS,CAAC,EAClD,GAAG,UAAU;AAMX,YAHoB,uBADlB,6BAA6B,OAAO,kBAAkB,CAGvD,CACkB;MACnB,CACH,CAE2B,KAC1B,GAAG,MAAM,WAAW,GAAG,KAAK,CAAC,EAC7B,GAAG,MAAM,gBAAgB,GAAG,CAAC,EAC7B,GAAG,OAAO,aAAa;AACrB,SAAI,SAAS,cAAc,KACzB,QAAO,GAAG,KAAK;MACb,MAAM;MACN,SAAS;MACV,CAAC;AAEJ,YAAO,GAAG,QAAQ;MAChB;MACA,YAAY,SAAS;MACtB,CAAC;MACF,EACF,GAAG,OAAO,EAAE,UAAU,iBAAiB;KACrC,MAAM,eAAe,yBACnB,WAAW,GACZ;KACD,MAAM,YAAY,WAAW;KAE7B,IAAI;AACJ,SAAI,UAAU,oBAAoB,CAChC,aAAY,UAAU,WAAW;UAC5B;MACL,MAAM,UAAU,UAAU,MAAM;AAChC,kBACE,YAAY,YAAY,MACpB,qBACA,YAAY,YAAY,MACtB,qBACA;;KAkCV,MAAM,UA5BF;OACD,2BAA2B;OAC1B,MAAM,MAAM,UAAU,KAAK;OAC3B,MAAM,SAAS,IAAI,WAAW,GAAG;OACjC,IAAI,KAAK,IAAI;AACb,YAAK,IAAI,IAAI,IAAI,KAAK,GAAG,KAAK;AAC5B,eAAO,KAAK,OAAO,KAAK,KAAM;AAC9B,eAAO;;OAET,MAAM,SAAS,IAAI,WAAW,GAAG;OACjC,IAAI,KAAK,IAAI;AACb,YAAK,IAAI,IAAI,IAAI,KAAK,GAAG,KAAK;AAC5B,eAAO,KAAK,OAAO,KAAK,KAAM;AAC9B,eAAO;;OAET,MAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,aAAM,KAAK;AACX,aAAM,IAAI,QAAQ,EAAE;AACpB,aAAM,IAAI,QAAQ,GAAG;AACrB,cAAO,GAAG,QAAQ,MAAM;;OAEzB,2BAA2B;OAC1B,MAAM,MAAM,UAAU,KAAK;OAC3B,MAAM,YAAY,IAAI,aAAa,IAAI,GAAG,IAAI,EAAE;AAChD,cAAO,GAAG,QAAQ,UAAU,aAAa,CAAC;;MAE7C,CAEwB;AACzB,aACE,UACI,SAAS,GACT,GAAG,KAAK;MACN,MAAM;MACN,SAAS,0BAA0B;MACpC,CAAC,EACN,KACA,GAAG,OAAO,mBACR,GAAG,KAAK;MACN,IAAI,YAAY;OACd,MAAM,aACJ,OAAO,cAAc;OACvB,MAAM,WAAW,OAAO,YAAY;AAGpC,aADW,OAAO,KAAK,IAAI,KAAK,OAAO,CAC9B,SAAS,OAAO;QACvB;QACA,UAAU,SAAS;QACnB,mBAAmB;QACpB,CAAC;AAEF,aAAM,oBAAoB,KAAK;QAC7B;QACA;QACA,WAAW,eAAe,OAAO,MAC/B,eAAe,YACf,eAAe,aACb,eAAe,WAClB;QACD;QACA,SAAS,SAAS;QAClB,YAAY,OAAO;QACnB;QACA;QACA,MAAM,OAAO;QACb,WAAW,KAAK,KAAK;QACtB,CAAC;AAOF,cAAO;QACL,MAAM;QACN,UAPmB,MAAM,WAAW,KAAK;SACzC;SACA,gBAAgB;SACjB,CAAC;QAKD;;MAEH,WACE,GAAG,MAAM;OACP,MAAM;OACN,SAAS;OACV,CAAC;MACL,CAAC,CACH,CACF;MACD,CACH;KACD,CACH,CACF,CACF;GACH,cAAc,MACZ,mBAAmB,SAAS,CAAC,KAC3B,GAAG,OAAO,OAAO;IACf,MAAM,YAAY,IAAI,WAAW,GAAG;AACpC,WAAO,gBAAgB,UAAU;IACjC,MAAM,gBAAgB,yBACpB,IAAI,WAAW,OAAO,UAAU,CAAC,CAClC;AAED,WAAO,GAAG,KAAK;KACb,IAAI,YAAY;MACd,MAAM,WAAW,MAAM,aAAa,IAAI;AACxC,YAAM,sBAAsB,KAAK;OAC/B;OACA,WAAW;OACZ,CAAC;MAEF,IAAI;AAOJ,UAAI,OAAO,OAAO;OAChB,MAAM,OAAO,MAAM,yBACjB,KACA,OAAO,MACR;AACD,WAAI,MAAM;QACR,MAAM,WAAW,MAAM,sBACrB,KACA,KAAK,IACN;AACD,YAAI,SAAS,SAAS,EACpB,oBAAmB,SAAS,KAAK,QAAQ;SACvC,MAAM;SACN,IAAI,GAAG;SACP,YAAY,GAAG;SAChB,EAAE;;;MAKT,MAAM,UAA+B;OACnC,WAAW,yBAAyB,UAAU;OAC9C,SAAS,GAAG;OACZ,MAAM,GAAG;OACT,kBAAkB,GAAG;OACtB;AAED,UAAI,iBACF,SAAQ,mBAAmB;AAG7B,aAAO;OACL,MAAM;OACN;OACA;OACD;;KAEH,WACE,GAAG,MAAM;MACP,MAAM;MACN,SAAS;MACV,CAAC;KACL,CAAC;KACF,CACH;GACH,aAAa,MACX,GAAG,IACD,mBAAmB,SAAS,EAC5B,yBAAyB,KAAK,SAAS,CACxC,CAAC,KACA,GAAG,OAAO,CAAC,IAAI,cAAc;IAC3B,MAAM,iBAAiB,6BACrB,OAAO,eACR;IACD,MAAM,aAAa,oBAAoB,eAAe;AAkBtD,WAhB6B,GAAG,QAAQ,WAAW,CAAC,KAClD,GAAG,MACD,qBAAqB,eAAe,KAAK,eAAe,CACzD,EACD,GAAG,MAAM,aAAa,GAAG,CAAC,EAC1B,GAAG,MAAM,0BAA0B,KAAK,SAAS,CAAC,EAClD,GAAG,YACD,OAAO,gBAAgB,OACnB,GAAG,QAAQ,OAAO,aAAuB,GACzC,GAAG,KAAK;KACN,MAAM;KACN,SAAS;KACV,CAAC,CACP,CACF,CAE2B,KAC1B,GAAG,OAAO,iBACR,GAAG,KAAK;KACN,UAAU,2BAA2B,KAAK,aAAa;KACvD,WACE,GAAG,MAAM;MACP,MAAM;MACN,SAAS;MACV,CAAC;KACL,CAAC,CAAC,KACD,GAAG,OAAO,YACR,UACI,GAAG,QAAQ,QAAQ,GACnB,GAAG,KAAK;KACN,MAAM;KACN,SAAS;KACV,CAAC,CACP,CACF,CACF,EACD,GAAG,OAAO,YAAY;KACpB,MAAM,yBAAyB,6BAC7B,OAAO,kBACR;KACD,MAAM,oBAAoB,uBACxB,uBACD;KAED,MAAM,YAAY,6BAChB,OAAO,UACR;KAKD,MAAM,cAAc,OAJK,gCACvB,wBACA,eACD,CAC2C;AA+E5C,YA7E+B,GAAG,QAChC,kBACD,CAAC,KACA,GAAG,MAAM,WAAW,GAAG,KAAK,CAAC,EAC7B,GAAG,MAAM,gBAAgB,GAAG,CAAC,CAC9B,CAEkD,KACjD,GAAG,YAAY;MACb,MAAM,uBAAuB,IAAI,WAC/B,QAAQ,UACT;MA0CD,MAAM,UAtCF;QACD,2BAA2B;AAY1B,eALc,qBANM,oBAClB,MACA,qBACD,EAKC,aAHA,yBAAyB,UAAU,CAKpC,GAEG,GAAG,QAAQ,OAAkB,GAC7B,GAAG,KAAK;SACN,MAAM;SACN,SAAS;SACV,CAAC;;QAEP,2BAA2B;AAS1B,eANc,8BADZ,wBAAwB,qBAAqB,EAG7C,wBACA,aACA,UACD,GAEG,GAAG,QAAQ,OAAkB,GAC7B,GAAG,KAAK;SACN,MAAM;SACN,SAAS;SACV,CAAC;;OAET,CAEiC,QAAQ;AAC1C,aAAO,UACH,SAAS,GACT,GAAG,KAAK;OACN,MAAM;OACN,SAAS,0BAA0B,QAAQ;OAC5C,CAAC;OACN,CACH,CAE8C,KAC7C,GAAG,YACD,QAAQ,YAAY,KACpB,kBAAkB,qBAAqB,KACvC,kBAAkB,oBAAoB,QAAQ,UAC1C,GAAG,KAAK;MACN,MAAM;MACN,SACE;MACH,CAAC,GACF,GAAG,QAAQ,kBAAkB,CAClC,CACF,CAEyB,KACxB,GAAG,YACD,GAAG,KAAK;MACN,IAAI,YAAY;AACd,aAAM,2BACJ,KACA,QAAQ,KACR,kBAAkB,kBAClB,KAAK,KAAK,CACX;AAOD,cAAO;QACL,MAAM;QACN,UAPmB,MAAM,WAAW,KAAK;SACzC,QAAQ,QAAQ;SAChB,gBAAgB;SACjB,CAAC;QAKD;;MAEH,WACE,GAAG,MAAM;OACP,MAAM;OACN,SAAS;OACV,CAAC;MACL,CAAC,CACH,CACF;MACD,CACH;KACD,CACH;GACJ,CAAC;GAEF,CACH"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"redirects.js","names":[],"sources":["../../src/server/redirects.ts"],"sourcesContent":["import { Cv } from \"@robelest/fx/convex\";\n\nimport { ConvexAuthMaterializedConfig } from \"./types\";\nimport { requireEnv } from \"./utils\";\n\n/** @internal */\nexport async function redirectAbsoluteUrl(\n config: ConvexAuthMaterializedConfig,\n params: { redirectTo: unknown },\n) {\n if (params.redirectTo === undefined) {\n return requireEnv(\"SITE_URL\").replace(/\\/$/, \"\");\n }\n if (typeof params.redirectTo !== \"string\") {\n throw Cv.error({\n code: \"INVALID_REDIRECT\",\n message: `Expected \\`redirectTo\\` to be a string, got ${params.redirectTo as any}`,\n });\n }\n const redirectCallback =\n config.callbacks?.redirect ?? defaultRedirectCallback;\n try {\n return await redirectCallback({ redirectTo: params.redirectTo });\n } catch {\n throw Cv.error({\n code: \"INTERNAL_ERROR\",\n message: \"An unexpected error occurred.\",\n });\n }\n}\n\nasync function defaultRedirectCallback({ redirectTo }: { redirectTo: string }) {\n // Resolve relative paths against SITE_URL; absolute URLs are passed through\n // as-is. The developer is trusted to provide valid redirect targets.\n if (redirectTo.startsWith(\"?\") || redirectTo.startsWith(\"/\")) {\n return `${requireEnv(\"SITE_URL\").replace(/\\/$/, \"\")}${redirectTo}`;\n }\n return redirectTo;\n}\n\n// Temporary work-around because Convex doesn't support\n// schemes other than http and https.\n/** @internal */\nexport function setURLSearchParam(\n absoluteUrl: string,\n param: string,\n value: string,\n) {\n const pattern = /([^:]+):(.*)/;\n const [, scheme, rest] = absoluteUrl.match(pattern)!;\n const hasNoDomain = /^\\/\\/(?:\\/|$|\\?)/.test(rest);\n const startsWithPath = hasNoDomain && rest.startsWith(\"///\");\n const url = new URL(\n `http:${hasNoDomain ? \"//googblibok\" + rest.slice(2) : rest}`,\n );\n url.searchParams.set(param, value);\n const [, , withParam] = url.toString().match(pattern)!;\n return `${scheme}:${hasNoDomain ? (startsWithPath ? \"/\" : \"\") + \"//\" + withParam.slice(13) : withParam}`;\n}\n"],"mappings":";;;;;AAMA,eAAsB,oBACpB,QACA,QACA;AACA,KAAI,OAAO,eAAe,OACxB,QAAO,WAAW,WAAW,CAAC,QAAQ,OAAO,GAAG;AAElD,KAAI,OAAO,OAAO,eAAe,SAC/B,OAAM,GAAG,MAAM;EACb,MAAM;EACN,SAAS,+CAA+C,OAAO;EAChE,CAAC;CAEJ,MAAM,mBACJ,OAAO,WAAW,YAAY;AAChC,KAAI;AACF,SAAO,MAAM,iBAAiB,EAAE,YAAY,OAAO,YAAY,CAAC;SAC1D;AACN,QAAM,GAAG,MAAM;GACb,MAAM;GACN,SAAS;GACV,CAAC;;;AAIN,eAAe,wBAAwB,EAAE,cAAsC;AAG7E,KAAI,WAAW,WAAW,IAAI,IAAI,WAAW,WAAW,IAAI,CAC1D,QAAO,GAAG,WAAW,WAAW,CAAC,QAAQ,OAAO,GAAG,GAAG;AAExD,QAAO;;;AAMT,SAAgB,kBACd,aACA,OACA,OACA;CACA,MAAM,UAAU;CAChB,MAAM,GAAG,QAAQ,QAAQ,YAAY,MAAM,QAAQ;CACnD,MAAM,cAAc,mBAAmB,KAAK,KAAK;CACjD,MAAM,iBAAiB,eAAe,KAAK,WAAW,MAAM;CAC5D,MAAM,MAAM,IAAI,IACd,QAAQ,cAAc,iBAAiB,KAAK,MAAM,EAAE,GAAG,OACxD;AACD,KAAI,aAAa,IAAI,OAAO,MAAM;CAClC,MAAM,KAAK,aAAa,IAAI,UAAU,CAAC,MAAM,QAAQ;AACrD,QAAO,GAAG,OAAO,GAAG,eAAe,iBAAiB,MAAM,MAAM,OAAO,UAAU,MAAM,GAAG,GAAG"}
|
package/dist/server/refresh.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"refresh.js","names":[],"sources":["../../src/server/refresh.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport { ConvexError, GenericId } from \"convex/values\";\n\nimport { authDb } from \"./db\";\nimport { Doc, MutationCtx } from \"./types\";\nimport { ConvexAuthConfig } from \"./types\";\nimport {\n LOG_LEVELS,\n REFRESH_TOKEN_DIVIDER,\n logWithLevel,\n maybeRedact,\n} from \"./utils\";\n\nconst DEFAULT_SESSION_INACTIVE_DURATION_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n/** @internal */\nexport const REFRESH_TOKEN_REUSE_WINDOW_MS = 10 * 1000; // 10 seconds\n\n// ---------------------------------------------------------------------------\n// Refresh token CRUD\n// ---------------------------------------------------------------------------\n\n/**\n * Create a new refresh token for the given session.\n */\n/** @internal */\nexport async function createRefreshToken(\n ctx: MutationCtx,\n config: ConvexAuthConfig,\n sessionId: GenericId<\"Session\">,\n parentRefreshTokenId: GenericId<\"RefreshToken\"> | null,\n): Promise<GenericId<\"RefreshToken\">> {\n const expirationTime =\n Date.now() +\n (config.session?.inactiveDurationMs ??\n (process.env.AUTH_SESSION_INACTIVE_DURATION_MS !== undefined\n ? Number(process.env.AUTH_SESSION_INACTIVE_DURATION_MS)\n : undefined) ??\n DEFAULT_SESSION_INACTIVE_DURATION_MS);\n\n return authDb(ctx, config).refreshTokens.create({\n sessionId,\n expirationTime,\n parentRefreshTokenId: parentRefreshTokenId ?? undefined,\n }) as Promise<GenericId<\"RefreshToken\">>;\n}\n\n/**\n * Parse a compound refresh token string into its constituent IDs.\n */\n/** @internal */\nexport const parseRefreshToken = (\n refreshToken: string,\n): Fx<\n {\n refreshTokenId: GenericId<\"RefreshToken\">;\n sessionId: GenericId<\"Session\">;\n },\n ConvexError<any>\n> => {\n const [refreshTokenId, sessionId] = refreshToken.split(REFRESH_TOKEN_DIVIDER);\n const msg = `Can't parse refresh token: ${maybeRedact(refreshToken)}`;\n const refreshTokenIdFx: Fx<string, ConvexError<any>> = refreshTokenId != null\n ? Fx.succeed(refreshTokenId)\n : Cv.fail({ code: \"INVALID_REFRESH_TOKEN\", message: msg });\n\n return refreshTokenIdFx.pipe(\n Fx.chain((rtId) => {\n const sessionIdFx: Fx<string, ConvexError<any>> = sessionId != null\n ? Fx.succeed(sessionId)\n : Cv.fail({ code: \"INVALID_REFRESH_TOKEN\", message: msg });\n return sessionIdFx.pipe(\n Fx.map((sId) => ({\n refreshTokenId: rtId as GenericId<\"RefreshToken\">,\n sessionId: sId as GenericId<\"Session\">,\n })),\n );\n }),\n );\n};\n\n/**\n * Mark all refresh tokens descending from the given refresh token as invalid\n * immediately. Used when we detect token reuse — revoke the entire tree.\n */\n/** @internal */\nexport async function invalidateRefreshTokensInSubtree(\n ctx: MutationCtx,\n refreshToken: Doc<\"RefreshToken\">,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n const tokensToInvalidate = [refreshToken];\n const visited = new Set<GenericId<\"RefreshToken\">>([refreshToken._id]);\n let frontier: GenericId<\"RefreshToken\">[] = [refreshToken._id];\n while (frontier.length > 0) {\n const nextFrontier: GenericId<\"RefreshToken\">[] = [];\n for (const currentTokenId of frontier) {\n const children = (await db.refreshTokens.getChildren(\n refreshToken.sessionId,\n currentTokenId,\n )) as Doc<\"RefreshToken\">[];\n for (const child of children) {\n if (visited.has(child._id)) continue;\n visited.add(child._id);\n tokensToInvalidate.push(child);\n nextFrontier.push(child._id);\n }\n }\n frontier = nextFrontier;\n }\n await Fx.run(\n Fx.each(tokensToInvalidate, (token) =>\n token.firstUsedTime === undefined ||\n token.firstUsedTime > Date.now() - REFRESH_TOKEN_REUSE_WINDOW_MS\n ? Fx.promise(() =>\n db.refreshTokens.patch(token._id, {\n firstUsedTime: Date.now() - REFRESH_TOKEN_REUSE_WINDOW_MS,\n }),\n )\n : Fx.unit,\n ),\n );\n return tokensToInvalidate;\n}\n\n// ---------------------------------------------------------------------------\n// Validation pipeline — the core of refresh token handling\n// ---------------------------------------------------------------------------\n\n/**\n * Validate a refresh token and its associated session.\n *\n * Returns `null` on any validation failure (matching original semantics).\n * Each validation step is a small composable function chained with `Fx.chain`.\n * On failure, the error message is logged and the pipeline folds to `null`.\n */\n/** @internal */\nexport const refreshTokenIfValid = (\n ctx: MutationCtx,\n refreshTokenId: string,\n tokenSessionId: string,\n config: ConvexAuthConfig,\n): Fx<\n { session: Doc<\"Session\">; refreshTokenDoc: Doc<\"RefreshToken\"> } | null,\n never\n> => {\n const db = authDb(ctx, config);\n\n const fetchDoc = <T>(\n promise: () => Promise<T | null>,\n failMsg: string,\n ): Fx<T | null, never> =>\n Fx.from({ ok: promise, err: () => failMsg }).pipe(\n Fx.recover((msg) => {\n logWithLevel(LOG_LEVELS.ERROR, msg);\n return Fx.succeed(null as T | null);\n }),\n );\n\n // The entire validation is a single pipeline:\n // fetch token → not null → not expired → session matches → fetch session → not null → not expired → combine\n return fetchDoc(\n () =>\n db.refreshTokens.getById(\n refreshTokenId as GenericId<\"RefreshToken\">,\n ) as Promise<Doc<\"RefreshToken\"> | null>,\n \"Invalid refresh token format\",\n )\n .pipe(\n Fx.chain((doc) =>\n doc !== null ? Fx.succeed(doc) : Fx.fail(\"Invalid refresh token\"),\n ),\n Fx.chain((doc) =>\n doc.expirationTime >= Date.now()\n ? Fx.succeed(doc)\n : Fx.fail(\"Expired refresh token\"),\n ),\n Fx.chain((doc) =>\n doc.sessionId === tokenSessionId\n ? Fx.succeed(doc)\n : Fx.fail(\"Invalid refresh token session ID\"),\n ),\n )\n .pipe(\n Fx.chain((doc: Doc<\"RefreshToken\">) =>\n fetchDoc(\n () =>\n db.sessions.getById(\n doc.sessionId,\n ) as Promise<Doc<\"Session\"> | null>,\n \"Invalid refresh token session format\",\n ).pipe(\n Fx.chain((session) =>\n session !== null\n ? Fx.succeed(session)\n : Fx.fail(\"Invalid refresh token session\"),\n ),\n Fx.chain((session) =>\n session.expirationTime >= Date.now()\n ? Fx.succeed(session)\n : Fx.fail(\"Expired refresh token session\"),\n ),\n Fx.map((session) => ({\n session,\n refreshTokenDoc: doc,\n })),\n ),\n ),\n Fx.fold({\n ok: (result) => result,\n err: (msg) => {\n logWithLevel(LOG_LEVELS.ERROR, msg);\n return null;\n },\n }),\n );\n};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","names":[],"sources":["../../src/server/runtime.ts"],"mappings":";;;;;;;;;AAqJA;;;;;;;;;;;;;;iBAAgB,IAAA,CAAK,OAAA,EAAS,gBAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","names":["serializeCookie"],"sources":["../../src/server/runtime.ts"],"sourcesContent":["import { Fx } from \"@robelest/fx\";\nimport { Cv } from \"@robelest/fx/convex\";\nimport {\n GenericActionCtx,\n GenericDataModel,\n HttpRouter,\n actionGeneric,\n internalMutationGeneric,\n} from \"convex/server\";\nimport { v } from \"convex/values\";\nimport { serialize as serializeCookie } from \"cookie\";\n\nimport { configDefaults, listAvailableProviders } from \"./config\";\nimport { redirectToParamCookie, useRedirectToParam } from \"./cookies\";\nimport { createCoreDomains } from \"./core\";\nimport { GetProviderOrThrowFunc } from \"./crypto\";\nimport {\n getOidcConfig,\n getPublicOidcConfig,\n getSamlConfig,\n upsertProtocolConfig,\n withOidcSecretState,\n} from \"./enterprise/config\";\nimport { createEnterpriseDomain } from \"./enterprise/domain\";\nimport { addEnterpriseHttpRuntime } from \"./enterprise/http\";\nimport {\n normalizeEnterprisePolicy,\n patchEnterprisePolicy,\n} from \"./enterprise/policy\";\nimport {\n createServiceProviderMetadata,\n getSamlServiceProviderOptions,\n parseSamlIdpMetadata,\n} from \"./enterprise/saml\";\nimport { parseScimPath } from \"./enterprise/scim\";\nimport {\n enterpriseOidcProviderId,\n getEnterpriseOidcUrls,\n isEnterpriseSamlSourceActive,\n normalizeDomain,\n} from \"./enterprise/shared\";\nimport {\n addAuthRoutes,\n addOpenIdRoutes,\n convertErrorsToResponse,\n createHttpAction,\n createHttpContext,\n createHttpRoute,\n getCookies,\n} from \"./http\";\nimport {\n callCreateAccountFromCredentials,\n callInvalidateSessions,\n callModifyAccount,\n callRetrieveAccountWithCredentials,\n callSignOut,\n callUserOAuth,\n callVerifierSignature,\n storeArgs,\n storeImpl,\n} from \"./mutations/index\";\nimport { createOAuthAuthorizationURL, handleOAuthCallback } from \"./oauth\";\nimport { redirectAbsoluteUrl, setURLSearchParam } from \"./redirects\";\nimport { signInImpl } from \"./signin\";\nimport type {\n ConvexAuthConfig,\n FunctionReferenceFromExport,\n OAuthMaterializedConfig,\n Tokens,\n} from \"./types\";\nimport { MutationCtx } from \"./types\";\nimport {\n decryptSecret,\n encryptSecret,\n generateRandomString,\n LOG_LEVELS,\n logError,\n logWithLevel,\n sha256,\n} from \"./utils\";\nimport { requireEnv } from \"./utils\";\n\nconst ENTERPRISE_OIDC_CLIENT_SECRET_KIND = \"oidc_client_secret\" as const;\n\n/**\n * The type of the signIn Convex Action returned from the auth() helper.\n *\n * This type is exported for implementors of other client integrations.\n * However it is not stable, and may change until this library reaches 1.0.\n *\n * @internal\n */\nexport type SignInAction = FunctionReferenceFromExport<\n ReturnType<typeof Auth>[\"signIn\"]\n>;\n\n/** @internal */\nexport type SignInActionResult =\n | { kind: \"signedIn\"; tokens: Tokens | null }\n | { kind: \"redirect\"; redirect: string; verifier: string }\n | { kind: \"started\" }\n | { kind: \"passkeyOptions\"; options: Record<string, any>; verifier: string }\n | { kind: \"totpRequired\"; verifier: string }\n | {\n kind: \"totpSetup\";\n totpSetup: { uri: string; secret: string; totpId: string };\n verifier: string;\n }\n | {\n kind: \"deviceCode\";\n deviceCode: {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n verificationUriComplete: string;\n expiresIn: number;\n interval: number;\n };\n };\n/**\n * The type of the signOut Convex Action returned from the auth() helper.\n *\n * This type is exported for implementors of other client integrations.\n * However it is not stable, and may change until this library reaches 1.0.\n *\n * @internal\n */\nexport type SignOutAction = FunctionReferenceFromExport<\n ReturnType<typeof Auth>[\"signOut\"]\n>;\n\n/**\n * Configure the Convex Auth library. Returns an object with\n * functions and `auth` helper. You must export the functions\n * from `convex/auth.ts` to make them callable:\n *\n * ```ts filename=\"convex/auth.ts\"\n * import { createAuth } from \"@robelest/convex-auth/component\";\n * import { components } from \"./_generated/api\";\n *\n * export const auth = createAuth(components.auth, {\n * providers: [],\n * });\n * export const { signIn, signOut, store } = auth;\n * ```\n *\n * @returns An object with fields you should reexport from your\n * `convex/auth.ts` file.\n */\nexport function Auth(config_: ConvexAuthConfig) {\n const config = configDefaults(config_);\n const hasOAuth = config.providers.some(\n (provider) => provider.type === \"oauth\",\n );\n const hasSSO = config.providers.some((provider) => provider.type === \"sso\");\n const getProviderOrThrow: GetProviderOrThrowFunc = (\n id: string,\n allowExtraProviders: boolean = false,\n ) => {\n const provider =\n config.providers.find(\n (configuredProvider) => configuredProvider.id === id,\n ) ??\n (allowExtraProviders\n ? config.extraProviders.find(\n (configuredProvider) => configuredProvider.id === id,\n )\n : undefined);\n if (provider === undefined) {\n const detail =\n `Provider \\`${id}\\` is not configured, ` +\n `available providers are ${listAvailableProviders(config, allowExtraProviders)}.`;\n logWithLevel(LOG_LEVELS.ERROR, detail);\n throw Cv.error({\n code: \"PROVIDER_NOT_CONFIGURED\",\n message: detail,\n provider: id,\n });\n }\n return provider;\n };\n type ComponentCtx = Pick<\n GenericActionCtx<GenericDataModel>,\n \"runQuery\" | \"runMutation\"\n >;\n type ComponentReadCtx = Pick<GenericActionCtx<GenericDataModel>, \"runQuery\">;\n const getEnterpriseSecret = async (\n ctx: ComponentReadCtx | ComponentCtx,\n enterpriseId: string,\n kind: typeof ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n ) => {\n return await ctx.runQuery(config.component.public.enterpriseSecretGet, {\n enterpriseId,\n kind,\n });\n };\n const getEnterpriseOidcConfigWithSecret = async (\n ctx: ComponentReadCtx | ComponentCtx,\n enterprise: { _id: string; config?: unknown },\n ): Promise<Record<string, any>> => {\n const oidc = getOidcConfig(enterprise.config);\n const secret = await getEnterpriseSecret(\n ctx,\n enterprise._id,\n ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n );\n return {\n ...oidc,\n ...(secret\n ? { clientSecret: await decryptSecret(secret.ciphertext) }\n : {}),\n };\n };\n const INVITE_TOKEN_ALPHABET =\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\";\n const INVITE_TOKEN_LENGTH = 48;\n\n const enterpriseNotFoundError = \"Enterprise not found.\";\n\n const ENTERPRISE_CONTROL_ROUTE_BASE = \"/api/auth/sso\";\n\n const getPolicyFromEnterprise = (enterprise: { policy?: unknown }) =>\n normalizeEnterprisePolicy(enterprise.policy);\n\n const loadEnterpriseOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await ctx.runQuery(\n config.component.public.enterpriseGet,\n {\n enterpriseId,\n },\n );\n if (!enterprise) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: enterpriseNotFoundError,\n });\n }\n return enterprise;\n };\n\n const loadActiveEnterpriseOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);\n if (enterprise.status !== \"active\") {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Enterprise connection is not active.\",\n });\n }\n return enterprise;\n };\n\n const loadActiveEnterpriseSamlOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadEnterpriseOrThrow(ctx, enterpriseId);\n const loaded = {\n source: {\n kind: \"enterprise\" as const,\n id: enterpriseId,\n },\n config: enterprise.config,\n status: enterprise.status,\n enterprise,\n };\n if (!isEnterpriseSamlSourceActive(loaded)) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Enterprise connection is not active.\",\n });\n }\n const saml = getSamlConfig(loaded.config);\n if (!saml.idp?.metadataXml) {\n throw Cv.error({\n code: \"PROVIDER_NOT_CONFIGURED\",\n message: \"SAML is not configured for this enterprise.\",\n });\n }\n return { loaded, enterprise, saml };\n };\n\n const loadEnterpriseOidcOrThrow = async (\n ctx: ComponentReadCtx,\n enterpriseId: string,\n ) => {\n const enterprise = await loadActiveEnterpriseOrThrow(ctx, enterpriseId);\n const oidc = await getEnterpriseOidcConfigWithSecret(ctx, enterprise);\n if (oidc.enabled !== true) {\n throw Cv.error({\n code: \"PROVIDER_NOT_CONFIGURED\",\n message: \"OIDC is not configured for this enterprise.\",\n });\n }\n return { enterprise, oidc };\n };\n\n const validateEnterprisePolicy = (\n policy: ReturnType<typeof normalizeEnterprisePolicy>,\n ) => {\n const checks: Array<{\n name: string;\n ok: boolean;\n message?: string;\n }> = [];\n\n checks.push({ name: \"policy_version\", ok: policy.version === 1 });\n checks.push({\n name: \"jit_default_role_ids_present\",\n ok:\n policy.provisioning.jit.mode !== \"createUserAndMembership\" ||\n policy.provisioning.jit.defaultRoleIds.length > 0,\n message:\n policy.provisioning.jit.mode === \"createUserAndMembership\" &&\n policy.provisioning.jit.defaultRoleIds.length === 0\n ? \"At least one default roleId is required when JIT membership provisioning is enabled.\"\n : undefined,\n });\n checks.push({\n name: \"jit_default_role_ids_known\",\n ok: policy.provisioning.jit.defaultRoleIds.every(\n (roleId) => config.authorization.roles[roleId] !== undefined,\n ),\n message: policy.provisioning.jit.defaultRoleIds.every(\n (roleId) => config.authorization.roles[roleId] !== undefined,\n )\n ? undefined\n : \"JIT defaultRoleIds contains unknown roleIds.\",\n });\n checks.push({\n name: \"scim_reuse_supported\",\n ok:\n policy.provisioning.scimReuse.user === \"externalId\" ||\n policy.provisioning.scimReuse.user === \"none\",\n });\n\n return checks;\n };\n\n const recordEnterpriseAuditEvent = async (\n ctx: ComponentCtx,\n data: {\n enterpriseId: string;\n groupId: string;\n eventType: string;\n actorType: \"user\" | \"system\" | \"scim\" | \"api_key\" | \"webhook\";\n actorId?: string;\n subjectType: string;\n subjectId?: string;\n ok: boolean;\n requestId?: string;\n ip?: string;\n metadata?: Record<string, unknown>;\n },\n ) => {\n const { ok, ...rest } = data;\n return (await ctx.runMutation(\n config.component.public.enterpriseAuditEventCreate,\n {\n ...rest,\n status: ok ? \"success\" : \"failure\",\n occurredAt: Date.now(),\n },\n )) as string;\n };\n\n const emitEnterpriseWebhookDeliveries = async (\n ctx: ComponentCtx,\n data: {\n enterpriseId: string;\n eventType: string;\n payload: Record<string, unknown>;\n auditEventId?: string;\n },\n ) => {\n const endpoints = await ctx.runQuery(\n config.component.public.enterpriseWebhookEndpointList,\n { enterpriseId: data.enterpriseId },\n );\n for (const endpoint of endpoints) {\n if (\n endpoint.status !== \"active\" ||\n !endpoint.subscriptions.includes(data.eventType)\n ) {\n continue;\n }\n await ctx.runMutation(\n config.component.public.enterpriseWebhookDeliveryEnqueue,\n {\n enterpriseId: data.enterpriseId,\n endpointId: endpoint._id,\n auditEventId: data.auditEventId,\n eventType: data.eventType,\n payload: data.payload,\n nextAttemptAt: Date.now(),\n },\n );\n }\n };\n\n const getEnterpriseScimContext = async (\n ctx: ComponentReadCtx,\n request: Request,\n ) => {\n const authHeader = request.headers.get(\"Authorization\");\n if (!authHeader?.startsWith(\"Bearer \")) {\n throw Cv.error({\n code: \"MISSING_BEARER_TOKEN\",\n message: \"Missing or malformed Authorization: Bearer header.\",\n });\n }\n const token = authHeader.slice(7);\n const scimConfig = await ctx.runQuery(\n config.component.public.enterpriseScimConfigGetByTokenHash,\n { tokenHash: await sha256(token) },\n );\n if (!scimConfig || scimConfig.status !== \"active\") {\n throw Cv.error({\n code: \"INVALID_API_KEY\",\n message: \"Invalid SCIM token.\",\n });\n }\n const parsedPath = parseScimPath(new URL(request.url).pathname);\n if (parsedPath.enterpriseId !== scimConfig.enterpriseId) {\n throw Cv.error({\n code: \"INVALID_API_KEY\",\n message: \"SCIM token/tenant mismatch.\",\n });\n }\n const enterprise = await ctx.runQuery(\n config.component.public.enterpriseGet,\n {\n enterpriseId: scimConfig.enterpriseId,\n },\n );\n if (enterprise === null) {\n throw Cv.error({\n code: \"INVALID_PARAMETERS\",\n message: \"Enterprise not found.\",\n });\n }\n return { scimConfig, enterprise, parsedPath };\n };\n\n let auth: any;\n auth = {\n ...createCoreDomains({\n config,\n getAuth: () => auth,\n callInvalidateSessions,\n callCreateAccountFromCredentials,\n callRetrieveAccountWithCredentials,\n callModifyAccount,\n getEnrichCtx: () => enrichCtx,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n inviteTokenLength: INVITE_TOKEN_LENGTH,\n }),\n /**\n * SSO namespace — enterprise SSO connection management, domain, OIDC,\n * SAML, SCIM, audit, and webhook helpers.\n */\n sso: createEnterpriseDomain({\n config,\n getAuth: () => auth,\n normalizeEnterprisePolicy,\n normalizeDomain,\n getEnterpriseSecret,\n loadEnterpriseOrThrow,\n validateEnterprisePolicy,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n enterpriseNotFoundError,\n ENTERPRISE_OIDC_CLIENT_SECRET_KIND,\n requireEnv,\n generateRandomString,\n INVITE_TOKEN_ALPHABET,\n sha256,\n encryptSecret,\n upsertProtocolConfig,\n parseSamlIdpMetadata,\n createServiceProviderMetadata,\n getSamlServiceProviderOptions,\n getPublicOidcConfig,\n withOidcSecretState,\n getOidcConfig,\n getEnterpriseOidcUrls,\n enterpriseOidcProviderId,\n getPolicyFromEnterprise,\n patchEnterprisePolicy,\n }),\n };\n\n // HTTP wiring stays local to the factory because it still depends on a\n // dense mix of OAuth, SAML, SCIM, cookie, and response helpers.\n auth.http = {\n /**\n * Register core HTTP routes for JWT verification and OAuth sign-in.\n *\n * ```ts\n * import { httpRouter } from \"convex/server\";\n * import { auth } from \"./auth\";\n *\n * const http = httpRouter();\n *\n * auth.http.add(http);\n *\n * export default http;\n * ```\n *\n * The following routes are handled always:\n *\n * - `/.well-known/openid-configuration`\n * - `/.well-known/jwks.json`\n *\n * The following routes are handled if OAuth is configured:\n *\n * - `/api/auth/signin/*`\n * - `/api/auth/callback/*`\n *\n * @param http your HTTP router\n */\n add: (http: HttpRouter) => {\n addOpenIdRoutes(http, {\n getIssuer: () => requireEnv(\"CONVEX_SITE_URL\"),\n getJwks: () => requireEnv(\"JWKS\"),\n });\n\n addEnterpriseHttpRuntime({\n http,\n hasSSO,\n auth,\n config,\n routeBase: ENTERPRISE_CONTROL_ROUTE_BASE,\n requireEnv,\n loadActiveEnterpriseSamlOrThrow,\n loadEnterpriseOidcOrThrow,\n getEnterpriseScimContext,\n getPolicyFromEnterprise,\n normalizeEnterprisePolicy,\n recordEnterpriseAuditEvent,\n emitEnterpriseWebhookDeliveries,\n generateRandomString,\n inviteTokenAlphabet: INVITE_TOKEN_ALPHABET,\n callUserOAuth,\n callVerifierSignature,\n });\n\n if (hasOAuth) {\n addAuthRoutes(http, {\n handleSignIn: convertErrorsToResponse(400, async (ctx, request) => {\n const url = new URL(request.url);\n const pathParts = url.pathname.split(\"/\");\n const providerId = pathParts[pathParts.length - 1]!;\n if (providerId === null) {\n throw Cv.error({\n code: \"OAUTH_MISSING_PROVIDER\",\n message: \"Missing OAuth provider ID.\",\n });\n }\n const verifier = url.searchParams.get(\"code\");\n if (verifier === null) {\n throw Cv.error({\n code: \"OAUTH_MISSING_VERIFIER\",\n message: \"Missing sign-in verifier.\",\n });\n }\n const provider = getProviderOrThrow(providerId);\n\n const oauthConfig = provider as OAuthMaterializedConfig;\n const { redirect, cookies, signature } =\n await createOAuthAuthorizationURL(\n providerId,\n oauthConfig.provider,\n oauthConfig,\n );\n\n await callVerifierSignature(ctx, {\n verifier,\n signature,\n });\n\n const redirectTo = url.searchParams.get(\"redirectTo\");\n if (redirectTo !== null) {\n cookies.push(redirectToParamCookie(providerId, redirectTo));\n }\n\n const headers = new Headers({ Location: redirect });\n for (const { name, value, options } of cookies) {\n headers.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options as any),\n );\n }\n\n return new Response(null, { status: 302, headers });\n }),\n handleCallback: async (ctx, request) => {\n const url = new URL(request.url);\n const callbackPathParts = new URL(request.url).pathname.split(\"/\");\n const providerId = callbackPathParts[callbackPathParts.length - 1];\n if (!providerId) {\n throw Cv.error({\n code: \"OAUTH_MISSING_PROVIDER\",\n message: \"Missing OAuth provider ID.\",\n });\n }\n logWithLevel(\n LOG_LEVELS.DEBUG,\n \"Handling OAuth callback for provider:\",\n providerId,\n );\n const provider = getProviderOrThrow(providerId);\n\n const cookies = getCookies(request);\n\n const maybeRedirectTo = useRedirectToParam(provider.id, cookies);\n\n const destinationUrl = await redirectAbsoluteUrl(config, {\n redirectTo: maybeRedirectTo?.redirectTo,\n });\n\n const params = url.searchParams;\n\n if (\n request.headers.get(\"Content-Type\") ===\n \"application/x-www-form-urlencoded\"\n ) {\n const formData = await request.formData();\n formData.forEach((value, key) => {\n if (typeof value === \"string\") {\n params.append(key, value);\n }\n });\n }\n\n return Fx.run(\n Fx.from({\n ok: async () => {\n const oauthConfig = provider as OAuthMaterializedConfig;\n const result = await Fx.run(\n handleOAuthCallback(\n providerId,\n oauthConfig.provider,\n oauthConfig,\n Object.fromEntries(params.entries()),\n cookies,\n ),\n );\n const oauthCookies = result.cookies;\n const { id: profileId, ...profileData } = result.profile;\n const { signature } = result;\n\n const verificationCode = await callUserOAuth(ctx, {\n provider: providerId,\n providerAccountId: profileId,\n profile: profileData,\n signature,\n });\n\n const redirUrl = setURLSearchParam(\n destinationUrl,\n \"code\",\n verificationCode,\n );\n const redirHeaders = new Headers({ Location: redirUrl });\n redirHeaders.set(\"Cache-Control\", \"must-revalidate\");\n for (const { name, value, options } of [\n ...oauthCookies,\n ...(maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []),\n ] as any) {\n redirHeaders.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return new Response(null, {\n status: 302,\n headers: redirHeaders,\n });\n },\n err: (error) => error,\n }).pipe(\n Fx.recover((error) => {\n logError(error);\n const respHeaders = new Headers({\n Location: destinationUrl,\n });\n for (const { name, value, options } of maybeRedirectTo !== null\n ? [maybeRedirectTo.updatedCookie]\n : []) {\n respHeaders.append(\n \"Set-Cookie\",\n serializeCookie(name, value, options),\n );\n }\n return Fx.succeed(\n new Response(null, {\n status: 302,\n headers: respHeaders,\n }),\n );\n }),\n ),\n );\n },\n });\n }\n },\n\n /**\n * Resolve mixed HTTP auth for a raw `httpAction`.\n *\n * Checks session auth first, then falls back to `Authorization: Bearer sk_*`\n * API keys. This is the low-level helper for endpoints that intentionally\n * accept either browser sessions or API keys.\n * Pass `{ optional: true }` to get a null-shaped auth object instead of a\n * `NOT_SIGNED_IN` error.\n *\n * ```ts\n * http.route({\n * path: \"/api/data\",\n * method: \"GET\",\n * handler: httpAction(async (ctx, request) => {\n * const authContext = await auth.http.context(ctx, request);\n * return Response.json({\n * userId: authContext.userId,\n * source: authContext.source,\n * });\n * }),\n * });\n * ```\n */\n context: createHttpContext(auth),\n\n /**\n * Wrap an HTTP action handler with Bearer token authentication.\n *\n * Extracts the `Authorization: Bearer <key>` header, verifies the\n * API key via `auth.key.verify()`, and injects `ctx.key` with the\n * verified key info. Returns structured JSON error responses for\n * missing/invalid/revoked/expired/rate-limited keys.\n *\n * If the handler returns a plain object, it is auto-wrapped in a\n * `200 JSON` response. If it returns a `Response`, CORS headers\n * are merged and the response is passed through.\n *\n * ```ts\n * const handler = auth.http.action(async (ctx, request) => {\n * const data = await ctx.runQuery(api.data.get, { userId: ctx.key.userId });\n * return { data };\n * });\n * http.route({ path: \"/api/data\", method: \"GET\", handler });\n * ```\n *\n * @param handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.\n * @param options.scope - Optional scope check; returns 403 if the key lacks permission.\n * @param options.cors - CORS config; defaults to permissive (`*`).\n */\n action: createHttpAction(auth),\n\n /**\n * Register a Bearer-authenticated route **and** its OPTIONS preflight\n * in a single call.\n *\n * ```ts\n * auth.http.route(http, {\n * path: \"/api/messages\",\n * method: \"POST\",\n * handler: async (ctx, request) => {\n * const { body } = await request.json();\n * await ctx.runMutation(internal.messages.sendAsUser, {\n * userId: ctx.key.userId,\n * body,\n * });\n * return { success: true };\n * },\n * });\n * ```\n *\n * @param http - The Convex HTTP router.\n * @param routeConfig.path - The URL path to match.\n * @param routeConfig.method - HTTP method (GET, POST, PUT, PATCH, DELETE).\n * @param routeConfig.handler - Receives enriched `ctx` (with `ctx.key`) and the raw `Request`.\n * @param routeConfig.scope - Optional scope check; returns 403 if the key lacks permission.\n * @param routeConfig.cors - CORS config; defaults to permissive (`*`).\n */\n route: createHttpRoute(createHttpAction(auth)),\n };\n\n const enrichCtx = <DataModel extends GenericDataModel>(\n ctx: GenericActionCtx<DataModel>,\n ) => ({\n ...ctx,\n auth: {\n ...ctx.auth,\n config,\n account: auth.account,\n session: auth.session,\n member: auth.member,\n provider: auth.provider,\n },\n });\n\n return {\n /**\n * Helper for configuring HTTP actions.\n */\n auth,\n /**\n * Action called by the client to sign the user in.\n *\n * Also used for refreshing the session.\n */\n signIn: actionGeneric({\n args: {\n provider: v.optional(v.string()),\n params: v.optional(v.any()),\n verifier: v.optional(v.string()),\n refreshToken: v.optional(v.string()),\n calledBy: v.optional(v.string()),\n },\n handler: async (ctx, args): Promise<SignInActionResult> => {\n if (args.calledBy !== undefined) {\n logWithLevel(\"INFO\", `\\`auth:signIn\\` called by ${args.calledBy}`);\n }\n const provider =\n args.provider !== undefined\n ? getProviderOrThrow(args.provider)\n : null;\n const result = await signInImpl(enrichCtx(ctx), provider, args, {\n generateTokens: true,\n allowExtraProviders: false,\n });\n return Fx.run(\n Fx.match(result, result.kind, {\n redirect: (r) =>\n Fx.succeed({\n kind: \"redirect\" as const,\n redirect: r.redirect,\n verifier: r.verifier,\n }),\n signedIn: (r) =>\n Fx.succeed({\n kind: \"signedIn\" as const,\n tokens: r.signedIn?.tokens ?? null,\n }),\n refreshTokens: (r) =>\n Fx.succeed({\n kind: \"signedIn\" as const,\n tokens: r.signedIn?.tokens ?? null,\n }),\n started: () => Fx.succeed({ kind: \"started\" as const }),\n passkeyOptions: (r) =>\n Fx.succeed({\n kind: \"passkeyOptions\" as const,\n options: r.options,\n verifier: r.verifier,\n }),\n totpRequired: (r) =>\n Fx.succeed({\n kind: \"totpRequired\" as const,\n verifier: r.verifier,\n }),\n totpSetup: (r) =>\n Fx.succeed({\n kind: \"totpSetup\" as const,\n totpSetup: {\n uri: r.uri,\n secret: r.secret,\n totpId: r.totpId,\n },\n verifier: r.verifier,\n }),\n deviceCode: (r) =>\n Fx.succeed({\n kind: \"deviceCode\" as const,\n deviceCode: {\n deviceCode: r.deviceCode,\n userCode: r.userCode,\n verificationUri: r.verificationUri,\n verificationUriComplete: r.verificationUriComplete,\n expiresIn: r.expiresIn,\n interval: r.interval,\n },\n }),\n }),\n );\n },\n }),\n /**\n * Action called by the client to invalidate the current session.\n */\n signOut: actionGeneric({\n args: {},\n handler: async (ctx) => {\n await callSignOut(ctx);\n },\n }),\n\n /**\n * Internal mutation used by the library to read and write\n * to the database during signin and signout.\n */\n store: internalMutationGeneric({\n args: storeArgs,\n handler: async (ctx: MutationCtx, args) => {\n return storeImpl(ctx, args, getProviderOrThrow, config);\n },\n }),\n };\n}\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","names":[],"sources":["../../src/server/sessions.ts"],"sourcesContent":["import { Auth } from \"convex/server\";\nimport { GenericId } from \"convex/values\";\n\nimport { authDb } from \"./db\";\nimport { createRefreshToken } from \"./refresh\";\nimport { generateToken } from \"./tokens\";\nimport { Doc, MutationCtx, SessionInfo } from \"./types\";\nimport { ConvexAuthConfig } from \"./types\";\nimport {\n LOG_LEVELS,\n TOKEN_SUB_CLAIM_DIVIDER,\n REFRESH_TOKEN_DIVIDER,\n logWithLevel,\n maybeRedact,\n} from \"./utils\";\n\nconst DEFAULT_SESSION_TOTAL_DURATION_MS = 1000 * 60 * 60 * 24 * 30; // 30 days\n\n/** @internal */\nexport async function maybeGenerateTokensForSession(\n ctx: MutationCtx,\n config: ConvexAuthConfig,\n userId: GenericId<\"User\">,\n sessionId: GenericId<\"Session\">,\n generateTokens: boolean,\n): Promise<SessionInfo> {\n return {\n userId,\n sessionId,\n tokens: generateTokens\n ? await generateTokensForSession(ctx, config, {\n userId,\n sessionId,\n issuedRefreshTokenId: null,\n parentRefreshTokenId: null,\n })\n : null,\n };\n}\n\n/** @internal */\nexport async function createNewAndDeleteExistingSession(\n ctx: MutationCtx,\n config: ConvexAuthConfig,\n userId: GenericId<\"User\">,\n) {\n const db = authDb(ctx, config);\n const existingSessionId = await getAuthSessionId(ctx);\n if (existingSessionId !== null) {\n const existingSession = await db.sessions.getById(existingSessionId);\n if (existingSession !== null) {\n await deleteSession(ctx, existingSession, config);\n }\n }\n return await createSession(ctx, userId, config);\n}\n\n/** @internal */\nexport async function generateTokensForSession(\n ctx: MutationCtx,\n config: ConvexAuthConfig,\n args: {\n userId: GenericId<\"User\">;\n sessionId: GenericId<\"Session\">;\n issuedRefreshTokenId: GenericId<\"RefreshToken\"> | null;\n parentRefreshTokenId: GenericId<\"RefreshToken\"> | null;\n },\n) {\n const ids = { userId: args.userId, sessionId: args.sessionId };\n const refreshTokenId =\n args.issuedRefreshTokenId ??\n (await createRefreshToken(\n ctx,\n config,\n args.sessionId,\n args.parentRefreshTokenId,\n ));\n const result = {\n token: await generateToken(ids, config),\n refreshToken: `${refreshTokenId}${REFRESH_TOKEN_DIVIDER}${args.sessionId}`,\n };\n logWithLevel(\n LOG_LEVELS.DEBUG,\n `Generated token ${maybeRedact(result.token)} and refresh token ${maybeRedact(refreshTokenId)} for session ${maybeRedact(args.sessionId)}`,\n );\n return result;\n}\n\nasync function createSession(\n ctx: MutationCtx,\n userId: GenericId<\"User\">,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n const expirationTime =\n Date.now() +\n (config.session?.totalDurationMs ??\n (process.env.AUTH_SESSION_TOTAL_DURATION_MS !== undefined\n ? Number(process.env.AUTH_SESSION_TOTAL_DURATION_MS)\n : undefined) ??\n DEFAULT_SESSION_TOTAL_DURATION_MS);\n return (await db.sessions.create(\n userId,\n expirationTime,\n )) as GenericId<\"Session\">;\n}\n\n/** @internal */\nexport async function deleteSession(\n ctx: MutationCtx,\n session: Doc<\"Session\">,\n config: ConvexAuthConfig,\n) {\n const db = authDb(ctx, config);\n await db.sessions.delete(session._id);\n await db.refreshTokens.deleteAll(session._id);\n}\n\n/**\n * Return the current session ID from the auth identity subject.\n *\n * Internal helper used by auth runtime internals and `auth.session.current`.\n */\n/** @internal */\nexport async function getAuthSessionId(ctx: { auth: Auth }) {\n const identity = await ctx.auth.getUserIdentity();\n if (identity === null) {\n return null;\n }\n const [, sessionId] = identity.subject.split(TOKEN_SUB_CLAIM_DIVIDER);\n return sessionId as GenericId<\"Session\">;\n}\n"],"mappings":";;;;;;AAgBA,MAAM,oCAAoC,MAAO,KAAK,KAAK,KAAK;;AAGhE,eAAsB,8BACpB,KACA,QACA,QACA,WACA,gBACsB;AACtB,QAAO;EACL;EACA;EACA,QAAQ,iBACJ,MAAM,yBAAyB,KAAK,QAAQ;GAC1C;GACA;GACA,sBAAsB;GACtB,sBAAsB;GACvB,CAAC,GACF;EACL;;;AAIH,eAAsB,kCACpB,KACA,QACA,QACA;CACA,MAAM,KAAK,OAAO,KAAK,OAAO;CAC9B,MAAM,oBAAoB,MAAM,iBAAiB,IAAI;AACrD,KAAI,sBAAsB,MAAM;EAC9B,MAAM,kBAAkB,MAAM,GAAG,SAAS,QAAQ,kBAAkB;AACpE,MAAI,oBAAoB,KACtB,OAAM,cAAc,KAAK,iBAAiB,OAAO;;AAGrD,QAAO,MAAM,cAAc,KAAK,QAAQ,OAAO;;;AAIjD,eAAsB,yBACpB,KACA,QACA,MAMA;CACA,MAAM,MAAM;EAAE,QAAQ,KAAK;EAAQ,WAAW,KAAK;EAAW;CAC9D,MAAM,iBACJ,KAAK,wBACJ,MAAM,mBACL,KACA,QACA,KAAK,WACL,KAAK,qBACN;CACH,MAAM,SAAS;EACb,OAAO,MAAM,cAAc,KAAK,OAAO;EACvC,cAAc,GAAG,iBAAiB,wBAAwB,KAAK;EAChE;AACD,cACE,WAAW,OACX,mBAAmB,YAAY,OAAO,MAAM,CAAC,qBAAqB,YAAY,eAAe,CAAC,eAAe,YAAY,KAAK,UAAU,GACzI;AACD,QAAO;;AAGT,eAAe,cACb,KACA,QACA,QACA;CACA,MAAM,KAAK,OAAO,KAAK,OAAO;CAC9B,MAAM,iBACJ,KAAK,KAAK,IACT,OAAO,SAAS,oBACd,QAAQ,IAAI,mCAAmC,SAC5C,OAAO,QAAQ,IAAI,+BAA+B,GAClD,WACJ;AACJ,QAAQ,MAAM,GAAG,SAAS,OACxB,QACA,eACD;;;AAIH,eAAsB,cACpB,KACA,SACA,QACA;CACA,MAAM,KAAK,OAAO,KAAK,OAAO;AAC9B,OAAM,GAAG,SAAS,OAAO,QAAQ,IAAI;AACrC,OAAM,GAAG,cAAc,UAAU,QAAQ,IAAI;;;;;;;;AAS/C,eAAsB,iBAAiB,KAAqB;CAC1D,MAAM,WAAW,MAAM,IAAI,KAAK,iBAAiB;AACjD,KAAI,aAAa,KACf,QAAO;CAET,MAAM,GAAG,aAAa,SAAS,QAAQ,MAAM,wBAAwB;AACrE,QAAO"}
|
package/dist/server/signin.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|