stormblessed
stormblessed•3w ago

[Convex Auth] Clerk Integration with Convex

Clerk will automatically create a convex user for social sign ups but the same flow doesn't work for email sign ups. Convex user is not being created automatically for Email sign up flow while it works correctly for social signup and sign in. The following is the code for email password registration.
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [pendingVerification, setPendingVerification] = useState(false);
const [code, setCode] = useState("");
const [isLoading, setIsLoading] = useState(false);

const { isLoaded, signUp, setActive } = useSignUp();

const handleSignUp = async () => {
if (!isLoaded) return;
setIsLoading(true);

try {
await signUp.create({
emailAddress: email,
password,
});

await signUp.prepareEmailAddressVerification({ strategy: "email_code" });
setPendingVerification(true);
} catch (err: any) {
Alert.alert(
"Sign Up Error",
err.errors?.[0]?.message || "An error occurred while signing up",
[{ text: "OK", style: "default" }]
);
} finally {
setIsLoading(false);
}
};

const handleVerification = async () => {
if (!isLoaded) return;
setIsLoading(true);

try {
const completeSignUp = await signUp.attemptEmailAddressVerification({
code,
});

await setActive({ session: completeSignUp.createdSessionId });

// The _layout.tsx will handle the redirection
} catch (err: any) {
Alert.alert(
"Verification Error",
err.errors?.[0]?.message || "An error occurred during verification",
[{ text: "OK", style: "default" }]
);
} finally {
setIsLoading(false);
}
};
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [pendingVerification, setPendingVerification] = useState(false);
const [code, setCode] = useState("");
const [isLoading, setIsLoading] = useState(false);

const { isLoaded, signUp, setActive } = useSignUp();

const handleSignUp = async () => {
if (!isLoaded) return;
setIsLoading(true);

try {
await signUp.create({
emailAddress: email,
password,
});

await signUp.prepareEmailAddressVerification({ strategy: "email_code" });
setPendingVerification(true);
} catch (err: any) {
Alert.alert(
"Sign Up Error",
err.errors?.[0]?.message || "An error occurred while signing up",
[{ text: "OK", style: "default" }]
);
} finally {
setIsLoading(false);
}
};

const handleVerification = async () => {
if (!isLoaded) return;
setIsLoading(true);

try {
const completeSignUp = await signUp.attemptEmailAddressVerification({
code,
});

await setActive({ session: completeSignUp.createdSessionId });

// The _layout.tsx will handle the redirection
} catch (err: any) {
Alert.alert(
"Verification Error",
err.errors?.[0]?.message || "An error occurred during verification",
[{ text: "OK", style: "default" }]
);
} finally {
setIsLoading(false);
}
};
4 Replies
Convex Bot
Convex Bot•3w ago
Thanks for posting in <#1088161997662724167>. Reminder: If you have a Convex Pro account, use the Convex Dashboard to file support tickets. - Provide context: What are you trying to achieve, what is the end-user interaction, what are you seeing? (full error message, command output, etc.) - Use search.convex.dev to search Docs, Stack, and Discord all at once. - Additionally, you can post your questions in the Convex Community's <#1228095053885476985> channel to receive a response from AI. - Avoid tagging staff unless specifically instructed. Thank you!
stormblessed
stormblessedOP•3w ago
; the following is social login and email log in screen
const LoginScreen = () => {
const { startOAuthFlow: startGoogleOAuthFlow } = useOAuth({
strategy: "oauth_google",
});
const { startOAuthFlow: startAppleOAuthFlow } = useOAuth({
strategy: "oauth_apple",
});
const { signOut } = useAuth();
const { colors } = useColors();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const { signIn, setActive, isLoaded } = useSignIn();
const { signUp } = useSignUp();
const router = useRouter();

const handleEmailSignIn = async () => {
if (!isLoaded) return;
setIsLoading(true);
try {
const completeSignIn = await signIn.create({
identifier: email,
password,
});
await setActive({ session: completeSignIn.createdSessionId });
// The _layout.tsx will handle the redirection
} catch (err: any) {
Alert.alert(
"Sign In Error",
err.errors?.[0]?.message || "An error occurred while signing in",
[{ text: "OK", style: "default" }]
);
} finally {
setIsLoading(false);
}
};

...
const LoginScreen = () => {
const { startOAuthFlow: startGoogleOAuthFlow } = useOAuth({
strategy: "oauth_google",
});
const { startOAuthFlow: startAppleOAuthFlow } = useOAuth({
strategy: "oauth_apple",
});
const { signOut } = useAuth();
const { colors } = useColors();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [isLoading, setIsLoading] = useState(false);
const { signIn, setActive, isLoaded } = useSignIn();
const { signUp } = useSignUp();
const router = useRouter();

const handleEmailSignIn = async () => {
if (!isLoaded) return;
setIsLoading(true);
try {
const completeSignIn = await signIn.create({
identifier: email,
password,
});
await setActive({ session: completeSignIn.createdSessionId });
// The _layout.tsx will handle the redirection
} catch (err: any) {
Alert.alert(
"Sign In Error",
err.errors?.[0]?.message || "An error occurred while signing in",
[{ text: "OK", style: "default" }]
);
} finally {
setIsLoading(false);
}
};

...
const handleOAuthError = async (error: any) => {
if (error.message?.includes("single session mode")) {
try {
await signOut();
// Retry the last OAuth flow after signing out
return true;
} catch (signOutError) {
console.error("Error signing out:", signOutError);
}
}
Alert.alert(
"Sign In Error",
"An error occurred while signing in. Please try again.",
[{ text: "OK", style: "default" }]
);
console.error("OAuth error", error);
return false;
};

const handleOAuthSuccess = async (
createdSessionId: string,
setActiveFunc: any
) => {
try {
await setActiveFunc({ session: createdSessionId });
// The _layout.tsx will handle the redirection
} catch (err) {
console.error("Error setting active session:", err);
Alert.alert(
"Sign In Error",
"An error occurred while completing sign in",
[{ text: "OK", style: "default" }]
);
}
};

const handleGoogleLogin = async () => {
try {
const { createdSessionId, setActive } = await startGoogleOAuthFlow();
if (createdSessionId) {
await handleOAuthSuccess(createdSessionId, setActive);
}
} catch (err) {
const shouldRetry = await handleOAuthError(err);
if (shouldRetry) {
handleGoogleLogin();
}
}
};

const handleAppleLogin = async () => {
try {
const { createdSessionId, setActive } = await startAppleOAuthFlow();
if (createdSessionId) {
await handleOAuthSuccess(createdSessionId, setActive);
}
} catch (err) {
const shouldRetry = await handleOAuthError(err);
if (shouldRetry) {
handleAppleLogin();
}
}
};
const handleOAuthError = async (error: any) => {
if (error.message?.includes("single session mode")) {
try {
await signOut();
// Retry the last OAuth flow after signing out
return true;
} catch (signOutError) {
console.error("Error signing out:", signOutError);
}
}
Alert.alert(
"Sign In Error",
"An error occurred while signing in. Please try again.",
[{ text: "OK", style: "default" }]
);
console.error("OAuth error", error);
return false;
};

const handleOAuthSuccess = async (
createdSessionId: string,
setActiveFunc: any
) => {
try {
await setActiveFunc({ session: createdSessionId });
// The _layout.tsx will handle the redirection
} catch (err) {
console.error("Error setting active session:", err);
Alert.alert(
"Sign In Error",
"An error occurred while completing sign in",
[{ text: "OK", style: "default" }]
);
}
};

const handleGoogleLogin = async () => {
try {
const { createdSessionId, setActive } = await startGoogleOAuthFlow();
if (createdSessionId) {
await handleOAuthSuccess(createdSessionId, setActive);
}
} catch (err) {
const shouldRetry = await handleOAuthError(err);
if (shouldRetry) {
handleGoogleLogin();
}
}
};

const handleAppleLogin = async () => {
try {
const { createdSessionId, setActive } = await startAppleOAuthFlow();
if (createdSessionId) {
await handleOAuthSuccess(createdSessionId, setActive);
}
} catch (err) {
const shouldRetry = await handleOAuthError(err);
if (shouldRetry) {
handleAppleLogin();
}
}
};
ballingt
ballingt•3w ago
To clarify, sounds like you're not using Convex Auth, you're using Clerk with Convex What's the question here, what is happening and what do you want to happen instead? It's hard to tell what's going on here without the imports, can you link to a full project or repro? It sounds like Clerk, Google OAuth, and convex are all involved. It sounds like you want to create a user in Convex? Do you have code for that? Is this code based on any example or guide? Oh reading more, maybe you are using Convex Auth? The Convex Auth and Clerk are mutually exclusive, you use one or the other. Which one do you want to use?
stormblessed
stormblessedOP•3w ago
Hi Tom, Thank you for your response. Let me clarify the setup: We are using Clerk for authentication (not Convex Auth), integrated with Convex as the backend. The specific issue is: Social sign-ups (Google, Apple) automatically create a Convex user Email/password sign-ups are not automatically creating a Convex user This behavior is inconsistent as both flows use Clerk as the auth provider The email registration flow uses Clerk's useSignUp hook with email verification: Create signup (signUp.create) Verify email with code (signUp.attemptEmailAddressVerification) Set active session (setActive) The social auth flow uses Clerk's useOAuth hook: 1. Start OAuth flow (startOAuthFlow) 2. Set active session on success Both flows successfully create Clerk users and sessions, but only the social flow is triggering Convex user creation. Would you be able to help identify why the email signup flow isn't triggering the same Convex user creation as the social flow? Happy to provide any additional configuration details needed. Let me know thanks 🙂 hi Tom sorry for bothering you it was a stupid mistake that you gave me good insight on. I fixed it. It was a small issue that was being reflected in the convex dashboard logs. the moment I spotted it I fixed it

Did you find this page helpful?