@robelest/convex-auth 0.0.1
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 +6 -0
- package/dist/bin.cjs +27733 -0
- package/dist/client/index.d.ts +49 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +283 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +36 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +295 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +121 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +78 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +4 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/index.d.ts +15 -0
- package/dist/component/index.d.ts.map +1 -0
- package/dist/component/index.js +13 -0
- package/dist/component/index.js.map +1 -0
- package/dist/component/public.d.ts +450 -0
- package/dist/component/public.d.ts.map +1 -0
- package/dist/component/public.js +528 -0
- package/dist/component/public.js.map +1 -0
- package/dist/component/schema.d.ts +107 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +26 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/providers/Anonymous.d.ts +50 -0
- package/dist/providers/Anonymous.d.ts.map +1 -0
- package/dist/providers/Anonymous.js +39 -0
- package/dist/providers/Anonymous.js.map +1 -0
- package/dist/providers/ConvexCredentials.d.ts +88 -0
- package/dist/providers/ConvexCredentials.d.ts.map +1 -0
- package/dist/providers/ConvexCredentials.js +37 -0
- package/dist/providers/ConvexCredentials.js.map +1 -0
- package/dist/providers/Email.d.ts +33 -0
- package/dist/providers/Email.d.ts.map +1 -0
- package/dist/providers/Email.js +50 -0
- package/dist/providers/Email.js.map +1 -0
- package/dist/providers/Password.d.ts +95 -0
- package/dist/providers/Password.d.ts.map +1 -0
- package/dist/providers/Password.js +174 -0
- package/dist/providers/Password.js.map +1 -0
- package/dist/providers/Phone.d.ts +22 -0
- package/dist/providers/Phone.d.ts.map +1 -0
- package/dist/providers/Phone.js +37 -0
- package/dist/providers/Phone.js.map +1 -0
- package/dist/server/convex_types.d.ts +17 -0
- package/dist/server/convex_types.d.ts.map +1 -0
- package/dist/server/convex_types.js +2 -0
- package/dist/server/convex_types.js.map +1 -0
- package/dist/server/cookies.d.ts +35 -0
- package/dist/server/cookies.d.ts.map +1 -0
- package/dist/server/cookies.js +34 -0
- package/dist/server/cookies.js.map +1 -0
- package/dist/server/implementation/db.d.ts +80 -0
- package/dist/server/implementation/db.d.ts.map +1 -0
- package/dist/server/implementation/db.js +59 -0
- package/dist/server/implementation/db.js.map +1 -0
- package/dist/server/implementation/index.d.ts +370 -0
- package/dist/server/implementation/index.d.ts.map +1 -0
- package/dist/server/implementation/index.js +521 -0
- package/dist/server/implementation/index.js.map +1 -0
- package/dist/server/implementation/mutations/createAccountFromCredentials.d.ts +33 -0
- package/dist/server/implementation/mutations/createAccountFromCredentials.d.ts.map +1 -0
- package/dist/server/implementation/mutations/createAccountFromCredentials.js +71 -0
- package/dist/server/implementation/mutations/createAccountFromCredentials.js.map +1 -0
- package/dist/server/implementation/mutations/createVerificationCode.d.ts +25 -0
- package/dist/server/implementation/mutations/createVerificationCode.d.ts.map +1 -0
- package/dist/server/implementation/mutations/createVerificationCode.js +84 -0
- package/dist/server/implementation/mutations/createVerificationCode.js.map +1 -0
- package/dist/server/implementation/mutations/index.d.ts +304 -0
- package/dist/server/implementation/mutations/index.d.ts.map +1 -0
- package/dist/server/implementation/mutations/index.js +108 -0
- package/dist/server/implementation/mutations/index.js.map +1 -0
- package/dist/server/implementation/mutations/invalidateSessions.d.ts +13 -0
- package/dist/server/implementation/mutations/invalidateSessions.d.ts.map +1 -0
- package/dist/server/implementation/mutations/invalidateSessions.js +35 -0
- package/dist/server/implementation/mutations/invalidateSessions.js.map +1 -0
- package/dist/server/implementation/mutations/modifyAccount.d.ts +23 -0
- package/dist/server/implementation/mutations/modifyAccount.d.ts.map +1 -0
- package/dist/server/implementation/mutations/modifyAccount.js +48 -0
- package/dist/server/implementation/mutations/modifyAccount.js.map +1 -0
- package/dist/server/implementation/mutations/refreshSession.d.ts +16 -0
- package/dist/server/implementation/mutations/refreshSession.d.ts.map +1 -0
- package/dist/server/implementation/mutations/refreshSession.js +116 -0
- package/dist/server/implementation/mutations/refreshSession.js.map +1 -0
- package/dist/server/implementation/mutations/retrieveAccountWithCredentials.d.ts +27 -0
- package/dist/server/implementation/mutations/retrieveAccountWithCredentials.d.ts.map +1 -0
- package/dist/server/implementation/mutations/retrieveAccountWithCredentials.js +55 -0
- package/dist/server/implementation/mutations/retrieveAccountWithCredentials.js.map +1 -0
- package/dist/server/implementation/mutations/signIn.d.ts +17 -0
- package/dist/server/implementation/mutations/signIn.d.ts.map +1 -0
- package/dist/server/implementation/mutations/signIn.js +26 -0
- package/dist/server/implementation/mutations/signIn.js.map +1 -0
- package/dist/server/implementation/mutations/signOut.d.ts +11 -0
- package/dist/server/implementation/mutations/signOut.d.ts.map +1 -0
- package/dist/server/implementation/mutations/signOut.js +24 -0
- package/dist/server/implementation/mutations/signOut.js.map +1 -0
- package/dist/server/implementation/mutations/userOAuth.d.ts +19 -0
- package/dist/server/implementation/mutations/userOAuth.d.ts.map +1 -0
- package/dist/server/implementation/mutations/userOAuth.js +84 -0
- package/dist/server/implementation/mutations/userOAuth.js.map +1 -0
- package/dist/server/implementation/mutations/verifier.d.ts +8 -0
- package/dist/server/implementation/mutations/verifier.d.ts.map +1 -0
- package/dist/server/implementation/mutations/verifier.js +19 -0
- package/dist/server/implementation/mutations/verifier.js.map +1 -0
- package/dist/server/implementation/mutations/verifierSignature.d.ts +15 -0
- package/dist/server/implementation/mutations/verifierSignature.d.ts.map +1 -0
- package/dist/server/implementation/mutations/verifierSignature.js +29 -0
- package/dist/server/implementation/mutations/verifierSignature.js.map +1 -0
- package/dist/server/implementation/mutations/verifyCodeAndSignIn.d.ts +21 -0
- package/dist/server/implementation/mutations/verifyCodeAndSignIn.d.ts.map +1 -0
- package/dist/server/implementation/mutations/verifyCodeAndSignIn.js +127 -0
- package/dist/server/implementation/mutations/verifyCodeAndSignIn.js.map +1 -0
- package/dist/server/implementation/provider.d.ts +6 -0
- package/dist/server/implementation/provider.d.ts.map +1 -0
- package/dist/server/implementation/provider.js +21 -0
- package/dist/server/implementation/provider.js.map +1 -0
- package/dist/server/implementation/rateLimit.d.ts +6 -0
- package/dist/server/implementation/rateLimit.d.ts.map +1 -0
- package/dist/server/implementation/rateLimit.js +76 -0
- package/dist/server/implementation/rateLimit.js.map +1 -0
- package/dist/server/implementation/redirects.d.ts +6 -0
- package/dist/server/implementation/redirects.d.ts.map +1 -0
- package/dist/server/implementation/redirects.js +40 -0
- package/dist/server/implementation/redirects.js.map +1 -0
- package/dist/server/implementation/refreshTokens.d.ts +40 -0
- package/dist/server/implementation/refreshTokens.d.ts.map +1 -0
- package/dist/server/implementation/refreshTokens.js +160 -0
- package/dist/server/implementation/refreshTokens.js.map +1 -0
- package/dist/server/implementation/sessions.d.ts +43 -0
- package/dist/server/implementation/sessions.d.ts.map +1 -0
- package/dist/server/implementation/sessions.js +94 -0
- package/dist/server/implementation/sessions.js.map +1 -0
- package/dist/server/implementation/signIn.d.ts +31 -0
- package/dist/server/implementation/signIn.d.ts.map +1 -0
- package/dist/server/implementation/signIn.js +148 -0
- package/dist/server/implementation/signIn.js.map +1 -0
- package/dist/server/implementation/tokens.d.ts +7 -0
- package/dist/server/implementation/tokens.d.ts.map +1 -0
- package/dist/server/implementation/tokens.js +18 -0
- package/dist/server/implementation/tokens.js.map +1 -0
- package/dist/server/implementation/types.d.ts +288 -0
- package/dist/server/implementation/types.d.ts.map +1 -0
- package/dist/server/implementation/types.js +182 -0
- package/dist/server/implementation/types.js.map +1 -0
- package/dist/server/implementation/users.d.ts +27 -0
- package/dist/server/implementation/users.d.ts.map +1 -0
- package/dist/server/implementation/users.js +181 -0
- package/dist/server/implementation/users.js.map +1 -0
- package/dist/server/implementation/utils.d.ts +17 -0
- package/dist/server/implementation/utils.d.ts.map +1 -0
- package/dist/server/implementation/utils.js +72 -0
- package/dist/server/implementation/utils.js.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +54 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/oauth/authorizationUrl.d.ts +13 -0
- package/dist/server/oauth/authorizationUrl.d.ts.map +1 -0
- package/dist/server/oauth/authorizationUrl.js +91 -0
- package/dist/server/oauth/authorizationUrl.js.map +1 -0
- package/dist/server/oauth/callback.d.ts +19 -0
- package/dist/server/oauth/callback.d.ts.map +1 -0
- package/dist/server/oauth/callback.js +173 -0
- package/dist/server/oauth/callback.js.map +1 -0
- package/dist/server/oauth/checks.d.ts +52 -0
- package/dist/server/oauth/checks.d.ts.map +1 -0
- package/dist/server/oauth/checks.js +106 -0
- package/dist/server/oauth/checks.js.map +1 -0
- package/dist/server/oauth/convexAuth.d.ts +12 -0
- package/dist/server/oauth/convexAuth.d.ts.map +1 -0
- package/dist/server/oauth/convexAuth.js +137 -0
- package/dist/server/oauth/convexAuth.js.map +1 -0
- package/dist/server/oauth/lib/utils/customFetch.d.ts +9 -0
- package/dist/server/oauth/lib/utils/customFetch.d.ts.map +1 -0
- package/dist/server/oauth/lib/utils/customFetch.js +11 -0
- package/dist/server/oauth/lib/utils/customFetch.js.map +1 -0
- package/dist/server/oauth/lib/utils/providers.d.ts +3 -0
- package/dist/server/oauth/lib/utils/providers.d.ts.map +1 -0
- package/dist/server/oauth/lib/utils/providers.js +7 -0
- package/dist/server/oauth/lib/utils/providers.js.map +1 -0
- package/dist/server/oauth/providers/oauth.d.ts +43 -0
- package/dist/server/oauth/providers/oauth.d.ts.map +1 -0
- package/dist/server/oauth/providers/oauth.js +3 -0
- package/dist/server/oauth/providers/oauth.js.map +1 -0
- package/dist/server/oauth/types.d.ts +24 -0
- package/dist/server/oauth/types.d.ts.map +1 -0
- package/dist/server/oauth/types.js +5 -0
- package/dist/server/oauth/types.js.map +1 -0
- package/dist/server/provider_utils.d.ts +76 -0
- package/dist/server/provider_utils.d.ts.map +1 -0
- package/dist/server/provider_utils.js +177 -0
- package/dist/server/provider_utils.js.map +1 -0
- package/dist/server/types.d.ts +412 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +2 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/utils.d.ts +3 -0
- package/dist/server/utils.d.ts.map +1 -0
- package/dist/server/utils.js +11 -0
- package/dist/server/utils.js.map +1 -0
- package/package.json +126 -0
- package/providers/Anonymous/package.json +6 -0
- package/providers/ConvexCredentials/package.json +6 -0
- package/providers/Email/package.json +6 -0
- package/providers/Password/package.json +6 -0
- package/providers/Phone/package.json +6 -0
- package/server/package.json +6 -0
- package/src/cli/command.ts +69 -0
- package/src/cli/generateKeys.ts +20 -0
- package/src/cli/index.ts +840 -0
- package/src/client/index.ts +415 -0
- package/src/component/_generated/api.ts +52 -0
- package/src/component/_generated/component.ts +586 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +156 -0
- package/src/component/convex.config.ts +5 -0
- package/src/component/index.ts +40 -0
- package/src/component/public.ts +607 -0
- package/src/component/schema.ts +35 -0
- package/src/providers/Anonymous.ts +79 -0
- package/src/providers/ConvexCredentials.ts +108 -0
- package/src/providers/Email.ts +60 -0
- package/src/providers/Password.ts +253 -0
- package/src/providers/Phone.ts +46 -0
- package/src/server/convex_types.ts +55 -0
- package/src/server/cookies.ts +42 -0
- package/src/server/implementation/db.ts +125 -0
- package/src/server/implementation/index.ts +815 -0
- package/src/server/implementation/mutations/createAccountFromCredentials.ts +113 -0
- package/src/server/implementation/mutations/createVerificationCode.ts +139 -0
- package/src/server/implementation/mutations/index.ts +157 -0
- package/src/server/implementation/mutations/invalidateSessions.ts +47 -0
- package/src/server/implementation/mutations/modifyAccount.ts +65 -0
- package/src/server/implementation/mutations/refreshSession.ts +188 -0
- package/src/server/implementation/mutations/retrieveAccountWithCredentials.ts +87 -0
- package/src/server/implementation/mutations/signIn.ts +51 -0
- package/src/server/implementation/mutations/signOut.ts +38 -0
- package/src/server/implementation/mutations/userOAuth.ts +112 -0
- package/src/server/implementation/mutations/verifier.ts +29 -0
- package/src/server/implementation/mutations/verifierSignature.ts +44 -0
- package/src/server/implementation/mutations/verifyCodeAndSignIn.ts +205 -0
- package/src/server/implementation/provider.ts +38 -0
- package/src/server/implementation/rateLimit.ts +105 -0
- package/src/server/implementation/redirects.ts +58 -0
- package/src/server/implementation/refreshTokens.ts +221 -0
- package/src/server/implementation/sessions.ts +155 -0
- package/src/server/implementation/signIn.ts +253 -0
- package/src/server/implementation/tokens.ts +29 -0
- package/src/server/implementation/types.ts +220 -0
- package/src/server/implementation/users.ts +286 -0
- package/src/server/implementation/utils.ts +91 -0
- package/src/server/index.ts +74 -0
- package/src/server/oauth/NOTICE.txt +21 -0
- package/src/server/oauth/README.md +7 -0
- package/src/server/oauth/authorizationUrl.ts +113 -0
- package/src/server/oauth/callback.ts +243 -0
- package/src/server/oauth/checks.ts +136 -0
- package/src/server/oauth/convexAuth.ts +168 -0
- package/src/server/oauth/lib/utils/customFetch.ts +18 -0
- package/src/server/oauth/lib/utils/providers.ts +12 -0
- package/src/server/oauth/providers/oauth.ts +56 -0
- package/src/server/oauth/types.ts +60 -0
- package/src/server/provider_utils.ts +222 -0
- package/src/server/types.ts +470 -0
- package/src/server/utils.ts +12 -0
- package/src/test.ts +24 -0
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { GenericId } from "convex/values";
|
|
2
|
+
import { Doc, MutationCtx } from "./types.js";
|
|
3
|
+
import { AuthProviderMaterializedConfig, ConvexAuthConfig } from "../types.js";
|
|
4
|
+
import { LOG_LEVELS, logWithLevel } from "./utils.js";
|
|
5
|
+
import { createAuthDb } from "./db.js";
|
|
6
|
+
|
|
7
|
+
type CreateOrUpdateUserArgs = {
|
|
8
|
+
type: "oauth" | "credentials" | "email" | "phone" | "verification";
|
|
9
|
+
provider: AuthProviderMaterializedConfig;
|
|
10
|
+
profile: Record<string, unknown> & {
|
|
11
|
+
email?: string;
|
|
12
|
+
phone?: string;
|
|
13
|
+
emailVerified?: boolean;
|
|
14
|
+
phoneVerified?: boolean;
|
|
15
|
+
};
|
|
16
|
+
shouldLinkViaEmail?: boolean;
|
|
17
|
+
shouldLinkViaPhone?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export async function upsertUserAndAccount(
|
|
21
|
+
ctx: MutationCtx,
|
|
22
|
+
sessionId: GenericId<"session"> | null,
|
|
23
|
+
account:
|
|
24
|
+
| { existingAccount: Doc<"account"> }
|
|
25
|
+
| {
|
|
26
|
+
providerAccountId: string;
|
|
27
|
+
secret?: string;
|
|
28
|
+
},
|
|
29
|
+
args: CreateOrUpdateUserArgs,
|
|
30
|
+
config: ConvexAuthConfig,
|
|
31
|
+
): Promise<{
|
|
32
|
+
userId: GenericId<"user">;
|
|
33
|
+
accountId: GenericId<"account">;
|
|
34
|
+
}> {
|
|
35
|
+
const userId = await defaultCreateOrUpdateUser(
|
|
36
|
+
ctx,
|
|
37
|
+
sessionId,
|
|
38
|
+
"existingAccount" in account ? account.existingAccount : null,
|
|
39
|
+
args,
|
|
40
|
+
config,
|
|
41
|
+
);
|
|
42
|
+
const accountId = await createOrUpdateAccount(ctx, userId, account, args, config);
|
|
43
|
+
return { userId, accountId };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function defaultCreateOrUpdateUser(
|
|
47
|
+
ctx: MutationCtx,
|
|
48
|
+
existingSessionId: GenericId<"session"> | null,
|
|
49
|
+
existingAccount: Doc<"account"> | null,
|
|
50
|
+
args: CreateOrUpdateUserArgs,
|
|
51
|
+
config: ConvexAuthConfig,
|
|
52
|
+
) {
|
|
53
|
+
logWithLevel(LOG_LEVELS.DEBUG, "defaultCreateOrUpdateUser args:", {
|
|
54
|
+
existingAccountId: existingAccount?._id,
|
|
55
|
+
existingSessionId,
|
|
56
|
+
args,
|
|
57
|
+
});
|
|
58
|
+
const existingUserId = existingAccount?.userId ?? null;
|
|
59
|
+
const authDb =
|
|
60
|
+
config.component !== undefined ? createAuthDb(ctx, config.component) : null;
|
|
61
|
+
if (config.callbacks?.createOrUpdateUser !== undefined) {
|
|
62
|
+
logWithLevel(LOG_LEVELS.DEBUG, "Using custom createOrUpdateUser callback");
|
|
63
|
+
return await config.callbacks.createOrUpdateUser(ctx, {
|
|
64
|
+
existingUserId,
|
|
65
|
+
...args,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const {
|
|
70
|
+
provider,
|
|
71
|
+
profile: {
|
|
72
|
+
emailVerified: profileEmailVerified,
|
|
73
|
+
phoneVerified: profilePhoneVerified,
|
|
74
|
+
...profile
|
|
75
|
+
},
|
|
76
|
+
} = args;
|
|
77
|
+
const emailVerified =
|
|
78
|
+
profileEmailVerified ??
|
|
79
|
+
((provider.type === "oauth" || provider.type === "oidc") &&
|
|
80
|
+
provider.allowDangerousEmailAccountLinking !== false);
|
|
81
|
+
const phoneVerified = profilePhoneVerified ?? false;
|
|
82
|
+
const shouldLinkViaEmail =
|
|
83
|
+
args.shouldLinkViaEmail || emailVerified || provider.type === "email";
|
|
84
|
+
const shouldLinkViaPhone =
|
|
85
|
+
args.shouldLinkViaPhone || phoneVerified || provider.type === "phone";
|
|
86
|
+
|
|
87
|
+
let userId = existingUserId;
|
|
88
|
+
if (existingUserId === null) {
|
|
89
|
+
const existingUserWithVerifiedEmailId =
|
|
90
|
+
typeof profile.email === "string" && shouldLinkViaEmail
|
|
91
|
+
? (await uniqueUserWithVerifiedEmail(ctx, profile.email, config))?._id ??
|
|
92
|
+
null
|
|
93
|
+
: null;
|
|
94
|
+
|
|
95
|
+
const existingUserWithVerifiedPhoneId =
|
|
96
|
+
typeof profile.phone === "string" && shouldLinkViaPhone
|
|
97
|
+
? (await uniqueUserWithVerifiedPhone(ctx, profile.phone, config))?._id ??
|
|
98
|
+
null
|
|
99
|
+
: null;
|
|
100
|
+
// If there is both email and phone verified user
|
|
101
|
+
// already we can't link.
|
|
102
|
+
if (
|
|
103
|
+
existingUserWithVerifiedEmailId !== null &&
|
|
104
|
+
existingUserWithVerifiedPhoneId !== null
|
|
105
|
+
) {
|
|
106
|
+
logWithLevel(
|
|
107
|
+
LOG_LEVELS.DEBUG,
|
|
108
|
+
`Found existing email and phone verified users, so not linking: email: ${existingUserWithVerifiedEmailId}, phone: ${existingUserWithVerifiedPhoneId}`,
|
|
109
|
+
);
|
|
110
|
+
userId = null;
|
|
111
|
+
} else if (existingUserWithVerifiedEmailId !== null) {
|
|
112
|
+
logWithLevel(
|
|
113
|
+
LOG_LEVELS.DEBUG,
|
|
114
|
+
`Found existing email verified user, linking: ${existingUserWithVerifiedEmailId}`,
|
|
115
|
+
);
|
|
116
|
+
userId = existingUserWithVerifiedEmailId;
|
|
117
|
+
} else if (existingUserWithVerifiedPhoneId !== null) {
|
|
118
|
+
logWithLevel(
|
|
119
|
+
LOG_LEVELS.DEBUG,
|
|
120
|
+
`Found existing phone verified user, linking: ${existingUserWithVerifiedPhoneId}`,
|
|
121
|
+
);
|
|
122
|
+
userId = existingUserWithVerifiedPhoneId;
|
|
123
|
+
} else {
|
|
124
|
+
logWithLevel(
|
|
125
|
+
LOG_LEVELS.DEBUG,
|
|
126
|
+
"No existing verified users found, creating new user",
|
|
127
|
+
);
|
|
128
|
+
userId = null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const userData = {
|
|
132
|
+
...(emailVerified ? { emailVerificationTime: Date.now() } : null),
|
|
133
|
+
...(phoneVerified ? { phoneVerificationTime: Date.now() } : null),
|
|
134
|
+
...profile,
|
|
135
|
+
};
|
|
136
|
+
const existingOrLinkedUserId = userId;
|
|
137
|
+
if (userId !== null) {
|
|
138
|
+
try {
|
|
139
|
+
if (authDb !== null) {
|
|
140
|
+
await authDb.users.patch(userId, userData);
|
|
141
|
+
} else {
|
|
142
|
+
await ctx.db.patch(userId, userData);
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Could not update user document with ID \`${userId}\`, ` +
|
|
147
|
+
`either the user has been deleted but their account has not, ` +
|
|
148
|
+
`or the profile data doesn't match the \`users\` table schema: ` +
|
|
149
|
+
`${(error as Error).message}`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
} else {
|
|
153
|
+
userId =
|
|
154
|
+
authDb !== null
|
|
155
|
+
? ((await authDb.users.insert(userData)) as GenericId<"user">)
|
|
156
|
+
: await ctx.db.insert("user", userData);
|
|
157
|
+
}
|
|
158
|
+
const afterUserCreatedOrUpdated = config.callbacks?.afterUserCreatedOrUpdated;
|
|
159
|
+
if (afterUserCreatedOrUpdated !== undefined) {
|
|
160
|
+
logWithLevel(
|
|
161
|
+
LOG_LEVELS.DEBUG,
|
|
162
|
+
"Calling custom afterUserCreatedOrUpdated callback",
|
|
163
|
+
);
|
|
164
|
+
await afterUserCreatedOrUpdated(ctx, {
|
|
165
|
+
userId,
|
|
166
|
+
existingUserId: existingOrLinkedUserId,
|
|
167
|
+
...args,
|
|
168
|
+
});
|
|
169
|
+
} else {
|
|
170
|
+
logWithLevel(
|
|
171
|
+
LOG_LEVELS.DEBUG,
|
|
172
|
+
"No custom afterUserCreatedOrUpdated callback, skipping",
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
return userId;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function uniqueUserWithVerifiedEmail(
|
|
179
|
+
ctx: MutationCtx,
|
|
180
|
+
email: string,
|
|
181
|
+
config: ConvexAuthConfig,
|
|
182
|
+
) {
|
|
183
|
+
if (config.component !== undefined) {
|
|
184
|
+
const authDb = createAuthDb(ctx, config.component);
|
|
185
|
+
return (await authDb.users.findByVerifiedEmail(email)) as Doc<"user"> | null;
|
|
186
|
+
}
|
|
187
|
+
const users = await ctx.db
|
|
188
|
+
.query("user")
|
|
189
|
+
.withIndex("email", (q) => q.eq("email", email))
|
|
190
|
+
.filter((q) => q.neq(q.field("emailVerificationTime"), undefined))
|
|
191
|
+
.take(2);
|
|
192
|
+
return users.length === 1 ? users[0] : null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function uniqueUserWithVerifiedPhone(
|
|
196
|
+
ctx: MutationCtx,
|
|
197
|
+
phone: string,
|
|
198
|
+
config: ConvexAuthConfig,
|
|
199
|
+
) {
|
|
200
|
+
if (config.component !== undefined) {
|
|
201
|
+
const authDb = createAuthDb(ctx, config.component);
|
|
202
|
+
return (await authDb.users.findByVerifiedPhone(phone)) as Doc<"user"> | null;
|
|
203
|
+
}
|
|
204
|
+
const users = await ctx.db
|
|
205
|
+
.query("user")
|
|
206
|
+
.withIndex("phone", (q) => q.eq("phone", phone))
|
|
207
|
+
.filter((q) => q.neq(q.field("phoneVerificationTime"), undefined))
|
|
208
|
+
.take(2);
|
|
209
|
+
return users.length === 1 ? users[0] : null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function createOrUpdateAccount(
|
|
213
|
+
ctx: MutationCtx,
|
|
214
|
+
userId: GenericId<"user">,
|
|
215
|
+
account:
|
|
216
|
+
| { existingAccount: Doc<"account"> }
|
|
217
|
+
| {
|
|
218
|
+
providerAccountId: string;
|
|
219
|
+
secret?: string;
|
|
220
|
+
},
|
|
221
|
+
args: CreateOrUpdateUserArgs,
|
|
222
|
+
config: ConvexAuthConfig,
|
|
223
|
+
) {
|
|
224
|
+
const authDb =
|
|
225
|
+
config.component !== undefined ? createAuthDb(ctx, config.component) : null;
|
|
226
|
+
const accountId =
|
|
227
|
+
"existingAccount" in account
|
|
228
|
+
? account.existingAccount._id
|
|
229
|
+
: authDb !== null
|
|
230
|
+
? ((await authDb.accounts.create({
|
|
231
|
+
userId,
|
|
232
|
+
provider: args.provider.id,
|
|
233
|
+
providerAccountId: account.providerAccountId,
|
|
234
|
+
secret: account.secret,
|
|
235
|
+
})) as GenericId<"account">)
|
|
236
|
+
: await ctx.db.insert("account", {
|
|
237
|
+
userId,
|
|
238
|
+
provider: args.provider.id,
|
|
239
|
+
providerAccountId: account.providerAccountId,
|
|
240
|
+
secret: account.secret,
|
|
241
|
+
});
|
|
242
|
+
// This is never used with the default `createOrUpdateUser` implementation,
|
|
243
|
+
// but it is used for manual linking via custom `createOrUpdateUser`:
|
|
244
|
+
if (
|
|
245
|
+
"existingAccount" in account &&
|
|
246
|
+
account.existingAccount.userId !== userId
|
|
247
|
+
) {
|
|
248
|
+
if (authDb !== null) {
|
|
249
|
+
await authDb.accounts.patch(accountId, { userId });
|
|
250
|
+
} else {
|
|
251
|
+
await ctx.db.patch(accountId, { userId });
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (args.profile.emailVerified) {
|
|
255
|
+
if (authDb !== null) {
|
|
256
|
+
await authDb.accounts.patch(accountId, { emailVerified: args.profile.email });
|
|
257
|
+
} else {
|
|
258
|
+
await ctx.db.patch(accountId, { emailVerified: args.profile.email });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (args.profile.phoneVerified) {
|
|
262
|
+
if (authDb !== null) {
|
|
263
|
+
await authDb.accounts.patch(accountId, { phoneVerified: args.profile.phone });
|
|
264
|
+
} else {
|
|
265
|
+
await ctx.db.patch(accountId, { phoneVerified: args.profile.phone });
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return accountId;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export async function getAccountOrThrow(
|
|
272
|
+
ctx: MutationCtx,
|
|
273
|
+
existingAccountId: GenericId<"account">,
|
|
274
|
+
config: ConvexAuthConfig,
|
|
275
|
+
) {
|
|
276
|
+
const existingAccount =
|
|
277
|
+
config.component !== undefined
|
|
278
|
+
? await createAuthDb(ctx, config.component).accounts.getById(existingAccountId)
|
|
279
|
+
: await ctx.db.get(existingAccountId);
|
|
280
|
+
if (existingAccount === null) {
|
|
281
|
+
throw new Error(
|
|
282
|
+
`Expected an account to exist for ID "${existingAccountId}"`,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
return existingAccount;
|
|
286
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { sha256 as rawSha256 } from "@oslojs/crypto/sha2";
|
|
2
|
+
import { encodeHexLowerCase } from "@oslojs/encoding";
|
|
3
|
+
import {
|
|
4
|
+
RandomReader,
|
|
5
|
+
generateRandomString as osloGenerateRandomString,
|
|
6
|
+
} from "@oslojs/crypto/random";
|
|
7
|
+
|
|
8
|
+
export const TOKEN_SUB_CLAIM_DIVIDER = "|";
|
|
9
|
+
export const REFRESH_TOKEN_DIVIDER = "|";
|
|
10
|
+
|
|
11
|
+
export function stringToNumber(value: string | undefined) {
|
|
12
|
+
return value !== undefined ? Number(value) : undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function sha256(input: string) {
|
|
16
|
+
return encodeHexLowerCase(rawSha256(new TextEncoder().encode(input)));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function generateRandomString(length: number, alphabet: string) {
|
|
20
|
+
const random: RandomReader = {
|
|
21
|
+
read(bytes) {
|
|
22
|
+
crypto.getRandomValues(bytes);
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return osloGenerateRandomString(random, alphabet, length);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function logError(error: unknown) {
|
|
30
|
+
logWithLevel(
|
|
31
|
+
LOG_LEVELS.ERROR,
|
|
32
|
+
error instanceof Error
|
|
33
|
+
? error.message + "\n" + error.stack?.replace("\\n", "\n")
|
|
34
|
+
: error,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const LOG_LEVELS = {
|
|
39
|
+
ERROR: "ERROR",
|
|
40
|
+
WARN: "WARN",
|
|
41
|
+
INFO: "INFO",
|
|
42
|
+
DEBUG: "DEBUG",
|
|
43
|
+
} as const;
|
|
44
|
+
type LogLevel = keyof typeof LOG_LEVELS;
|
|
45
|
+
|
|
46
|
+
export function logWithLevel(level: LogLevel, ...args: unknown[]) {
|
|
47
|
+
const configuredLogLevel =
|
|
48
|
+
LOG_LEVELS[
|
|
49
|
+
(process.env.AUTH_LOG_LEVEL as LogLevel | undefined) ?? "INFO"
|
|
50
|
+
] ?? "INFO";
|
|
51
|
+
switch (level) {
|
|
52
|
+
case "ERROR":
|
|
53
|
+
console.error(...args);
|
|
54
|
+
break;
|
|
55
|
+
case "WARN":
|
|
56
|
+
if (configuredLogLevel !== "ERROR") {
|
|
57
|
+
console.warn(...args);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
case "INFO":
|
|
61
|
+
if (configuredLogLevel === "INFO" || configuredLogLevel === "DEBUG") {
|
|
62
|
+
console.info(...args);
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
case "DEBUG":
|
|
66
|
+
if (configuredLogLevel === "DEBUG") {
|
|
67
|
+
console.debug(...args);
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const UNREDACTED_LENGTH = 5;
|
|
74
|
+
export function maybeRedact(value: string) {
|
|
75
|
+
if (value === "") {
|
|
76
|
+
return "";
|
|
77
|
+
}
|
|
78
|
+
const shouldRedact = process.env.AUTH_LOG_SECRETS !== "true";
|
|
79
|
+
if (shouldRedact) {
|
|
80
|
+
if (value.length < UNREDACTED_LENGTH * 2) {
|
|
81
|
+
return "<redacted>";
|
|
82
|
+
}
|
|
83
|
+
return (
|
|
84
|
+
value.substring(0, UNREDACTED_LENGTH) +
|
|
85
|
+
"<redacted>" +
|
|
86
|
+
value.substring(value.length - UNREDACTED_LENGTH)
|
|
87
|
+
);
|
|
88
|
+
} else {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { parse, serialize } from "cookie";
|
|
2
|
+
import { isLocalHost } from "./utils.js";
|
|
3
|
+
|
|
4
|
+
export type AuthCookieConfig = {
|
|
5
|
+
maxAge: number | null;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export type AuthCookies = {
|
|
9
|
+
token: string | null;
|
|
10
|
+
refreshToken: string | null;
|
|
11
|
+
verifier: string | null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function authCookieNames(host?: string) {
|
|
15
|
+
const prefix = isLocalHost(host) ? "" : "__Host-";
|
|
16
|
+
return {
|
|
17
|
+
token: `${prefix}__convexAuthJWT`,
|
|
18
|
+
refreshToken: `${prefix}__convexAuthRefreshToken`,
|
|
19
|
+
verifier: `${prefix}__convexAuthOAuthVerifier`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function parseAuthCookies(
|
|
24
|
+
cookieHeader: string | null | undefined,
|
|
25
|
+
host?: string,
|
|
26
|
+
): AuthCookies {
|
|
27
|
+
const names = authCookieNames(host);
|
|
28
|
+
const parsed = parse(cookieHeader ?? "");
|
|
29
|
+
return {
|
|
30
|
+
token: parsed[names.token] ?? null,
|
|
31
|
+
refreshToken: parsed[names.refreshToken] ?? null,
|
|
32
|
+
verifier: parsed[names.verifier] ?? null,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function serializeAuthCookies(
|
|
37
|
+
cookies: AuthCookies,
|
|
38
|
+
host?: string,
|
|
39
|
+
config: AuthCookieConfig = { maxAge: null },
|
|
40
|
+
) {
|
|
41
|
+
const names = authCookieNames(host);
|
|
42
|
+
const secure = !isLocalHost(host);
|
|
43
|
+
const base = {
|
|
44
|
+
path: "/",
|
|
45
|
+
httpOnly: true,
|
|
46
|
+
sameSite: "lax" as const,
|
|
47
|
+
secure,
|
|
48
|
+
};
|
|
49
|
+
const maxAge = config.maxAge ?? undefined;
|
|
50
|
+
return [
|
|
51
|
+
serialize(names.token, cookies.token ?? "", {
|
|
52
|
+
...base,
|
|
53
|
+
maxAge: cookies.token === null ? 0 : maxAge,
|
|
54
|
+
expires: cookies.token === null ? new Date(0) : undefined,
|
|
55
|
+
}),
|
|
56
|
+
serialize(names.refreshToken, cookies.refreshToken ?? "", {
|
|
57
|
+
...base,
|
|
58
|
+
maxAge: cookies.refreshToken === null ? 0 : maxAge,
|
|
59
|
+
expires: cookies.refreshToken === null ? new Date(0) : undefined,
|
|
60
|
+
}),
|
|
61
|
+
serialize(names.verifier, cookies.verifier ?? "", {
|
|
62
|
+
...base,
|
|
63
|
+
maxAge: cookies.verifier === null ? 0 : maxAge,
|
|
64
|
+
expires: cookies.verifier === null ? new Date(0) : undefined,
|
|
65
|
+
}),
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function shouldProxyAuthAction(pathname: string, apiRoute: string) {
|
|
70
|
+
if (apiRoute.endsWith("/")) {
|
|
71
|
+
return pathname === apiRoute || pathname === apiRoute.slice(0, -1);
|
|
72
|
+
}
|
|
73
|
+
return pathname === apiRoute || pathname === `${apiRoute}/`;
|
|
74
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Some code in this directory is derived from the Auth.js project
|
|
2
|
+
(https://github.com/nextauthjs/next-auth), and is used according to the terms
|
|
3
|
+
of that project's license.
|
|
4
|
+
|
|
5
|
+
---------
|
|
6
|
+
|
|
7
|
+
ISC License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2022-2024, Balázs Orbán
|
|
10
|
+
|
|
11
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
12
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
13
|
+
copyright notice and this permission notice appear in all copies.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
16
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
17
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
18
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
19
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
20
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
21
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
The code in this directory is meant to handle OAuth2 and OIDC flows.
|
|
2
|
+
|
|
3
|
+
The code is adapted from the @auth/core package, but since some of their types
|
|
4
|
+
and functions used are internal, they're copied over but with similar structure.
|
|
5
|
+
|
|
6
|
+
Everything that deviates from the original code is marked with a "ConvexAuth:"
|
|
7
|
+
comment.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// This file corresponds to packages/core/src/lib/actions/signin/authorization-url.ts in the @auth/core package (commit 5af1f30a32e64591abc50ae4d2dba4682e525431).
|
|
2
|
+
import * as checks from "./checks.js";
|
|
3
|
+
import { InternalOptions } from "./types.js";
|
|
4
|
+
import {
|
|
5
|
+
callbackUrl,
|
|
6
|
+
getAuthorizationSignature,
|
|
7
|
+
} from "./convexAuth.js";
|
|
8
|
+
import { Cookie } from "@auth/core/lib/utils/cookie.js";
|
|
9
|
+
import { logWithLevel } from "../implementation/utils.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generates an authorization/request token URL.
|
|
13
|
+
*
|
|
14
|
+
* [OAuth 2](https://www.oauth.com/oauth2-servers/authorization/the-authorization-request/)
|
|
15
|
+
*/
|
|
16
|
+
export async function getAuthorizationUrl(
|
|
17
|
+
// ConvexAuth: we don't accept a query argument
|
|
18
|
+
options: InternalOptions<"oauth" | "oidc">,
|
|
19
|
+
) {
|
|
20
|
+
const { provider } = options;
|
|
21
|
+
|
|
22
|
+
let url = provider.authorization?.url;
|
|
23
|
+
|
|
24
|
+
// ConvexAuth: ConvexAuth does slightly different logic to determine the authorization endpoint
|
|
25
|
+
const { as, authorization: authorizationEndpoint, configSource } = provider;
|
|
26
|
+
|
|
27
|
+
if (!authorizationEndpoint) {
|
|
28
|
+
throw new TypeError("Could not determine the authorization endpoint.");
|
|
29
|
+
}
|
|
30
|
+
if (!url) {
|
|
31
|
+
url = new URL(authorizationEndpoint.url);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const authParams = url.searchParams;
|
|
35
|
+
|
|
36
|
+
// ConvexAuth: The logic for the callback URL is different from Auth.js
|
|
37
|
+
const redirect_uri = callbackUrl(provider.id);
|
|
38
|
+
// TODO(ConvexAuth): Support redirect proxy URLs.
|
|
39
|
+
// If we do so, update state.create to take the data value as an origin parameter (see the Auth.js code for ref).
|
|
40
|
+
// let data: string | undefined;
|
|
41
|
+
// if (!options.isOnRedirectProxy && provider.redirectProxyUrl) {
|
|
42
|
+
// redirect_uri = provider.redirectProxyUrl;
|
|
43
|
+
// data = provider.callbackUrl;
|
|
44
|
+
// logger.debug("using redirect proxy", { redirect_uri, data });
|
|
45
|
+
// }
|
|
46
|
+
|
|
47
|
+
const params = Object.assign(
|
|
48
|
+
{
|
|
49
|
+
response_type: "code",
|
|
50
|
+
// clientId can technically be undefined, should we check this in assert.ts or rely on the Authorization Server to do it?
|
|
51
|
+
client_id: provider.clientId,
|
|
52
|
+
redirect_uri,
|
|
53
|
+
// @ts-expect-error TODO:
|
|
54
|
+
...provider.authorization?.params,
|
|
55
|
+
},
|
|
56
|
+
Object.fromEntries(url.searchParams.entries() ?? []),
|
|
57
|
+
// ConvexAuth: no query arguments are combined in the params
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
for (const k in params) authParams.set(k, params[k]);
|
|
61
|
+
|
|
62
|
+
const cookies: Cookie[] = [];
|
|
63
|
+
|
|
64
|
+
// ConvexAuth: no value passed for `origin` (Auth.js uses `data` from above)
|
|
65
|
+
const state = await checks.state.create(options);
|
|
66
|
+
if (state) {
|
|
67
|
+
authParams.set("state", state.value);
|
|
68
|
+
cookies.push(state.cookie);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ConvexAuth: We need to save the value of the codeVerifier.
|
|
72
|
+
let codeVerifier: string | undefined;
|
|
73
|
+
if (provider.checks?.includes("pkce")) {
|
|
74
|
+
// ConvexAuth: we check where the config came from to help decide which branch to take here
|
|
75
|
+
if (configSource === "discovered" && !as.code_challenge_methods_supported?.includes("S256")) {
|
|
76
|
+
// We assume S256 PKCE support, if the server does not advertise that,
|
|
77
|
+
// a random `nonce` must be used for CSRF protection.
|
|
78
|
+
if (provider.type === "oidc") provider.checks = ["nonce"];
|
|
79
|
+
} else {
|
|
80
|
+
const pkce = await checks.pkce.create(options);
|
|
81
|
+
authParams.set("code_challenge", pkce.codeChallenge);
|
|
82
|
+
authParams.set("code_challenge_method", "S256");
|
|
83
|
+
cookies.push(pkce.cookie);
|
|
84
|
+
codeVerifier = pkce.codeVerifier;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const nonce = await checks.nonce.create(options);
|
|
89
|
+
if (nonce) {
|
|
90
|
+
authParams.set("nonce", nonce.value);
|
|
91
|
+
cookies.push(nonce.cookie);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// TODO: This does not work in normalizeOAuth because authorization endpoint can come from discovery
|
|
95
|
+
// Need to make normalizeOAuth async
|
|
96
|
+
if (provider.type === "oidc" && !url.searchParams.has("scope")) {
|
|
97
|
+
url.searchParams.set("scope", "openid profile email");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
logWithLevel("DEBUG", "authorization url is ready", {
|
|
101
|
+
url,
|
|
102
|
+
cookies,
|
|
103
|
+
provider,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const convexAuthSignature = getAuthorizationSignature({
|
|
107
|
+
codeVerifier,
|
|
108
|
+
state: authParams.get("state") ?? undefined,
|
|
109
|
+
nonce: authParams.get("nonce") ?? undefined,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
return { redirect: url.toString(), cookies, signature: convexAuthSignature };
|
|
113
|
+
}
|