OAuth connections
Before you start
You must configure your application instance through the Clerk Dashboard for the social connection(s) that you want to use, as described at the top of the OAuth guide.
Create the sign-up and sign-in flow
When using OAuth, the sign-up and sign-in flows are equivalent. A successful OAuth flow consists of the following steps:
- Start the OAuth flow by calling
SignIn.authenticateWithRedirect(params)
orSignUp.authenticateWithRedirect(params)
. Note that both of these methods require aredirectUrl
param, which is the URL that the browser will be redirected to once the user authenticates with the OAuth provider. - Create a route at the URL that the
redirectUrl
param points to. The following example names this route/sso-callback
. This route should call theClerk.handleRedirectCallback()
method or simply render the prebuilt<AuthenticateWithRedirectCallback/>
component.
The following example shows two files:
- The sign-in page where the user can start the OAuth flow.
- The SSO callback page where the OAuth flow is completed.
'use client';
import * as React from 'react';
import { OAuthStrategy } from '@clerk/types';
import { useSignIn } from '@clerk/nextjs';
export default function OauthSignIn() {
const { signIn } = useSignIn();
if (!signIn) return null;
const signInWith = (strategy: OAuthStrategy) => {
return signIn.authenticateWithRedirect({
strategy,
redirectUrl: '/sign-up/sso-callback',
redirectUrlComplete: '/',
});
};
// Render a button for each supported OAuth provider
// you want to add to your app. This example uses only Google.
return (
<div>
<button onClick={() => signInWith('oauth_google')}>
Sign in with Google
</button>
</div>
);
}
import { AuthenticateWithRedirectCallback } from '@clerk/nextjs';
export default function SSOCallback() {
console.log('testing');
// Handle the redirect flow by rendering the
// prebuilt AuthenticateWithRedirectCallback component.
// This is the final step in the custom OAuth flow.
return <AuthenticateWithRedirectCallback />;
}
OAuth account transfer flows
It is common for users who are authenticating with OAuth to use a sign-in button when they mean to sign-up, and vice versa. For those cases, the SignIn
and SignUp
objects have a transferable
status that indicates whether the user can be transferred to the other flow.
If you would like to keep your sign-in and sign-up flows completely separate, then you can skip this section.
The following example shows how to handle these cases in your sign-in flow. The same logic can be applied to the sign-up flow; change the signIn.AuthenticateWithRedirect()
to signUp.authenticateWithRedirect()
.
'use client';
import * as React from 'react';
import { OAuthStrategy } from '@clerk/types';
import { useSignIn, useSignUp } from '@clerk/nextjs';
export default function OauthSignIn() {
const { signIn } = useSignIn();
const { signUp, setActive } = useSignUp();
if (!signIn || !signUp) return null;
const signInWith = (strategy: OAuthStrategy) => {
return signIn.authenticateWithRedirect({
strategy,
redirectUrl: '/sign-up/sso-callback',
redirectUrlComplete: '/',
});
};
async function handleSignIn(strategy: OAuthStrategy) {
if (!signIn || !signUp) return null;
// If the user has an account in your application, but does not yet
// have an OAuth account connected to it, you can transfer the OAuth
// account to the existing user account.
const userExistsButNeedsToSignIn =
signUp.verifications.externalAccount.status === 'transferable' &&
signUp.verifications.externalAccount.error?.code ===
'external_account_exists';
if (userExistsButNeedsToSignIn) {
const res = await signIn.create({ transfer: true });
if (res.status === 'complete') {
setActive({
session: res.createdSessionId,
});
}
}
// If the user has an OAuth account but does not yet
// have an account in your app, you can create an account
// for them using the OAuth information.
const userNeedsToBeCreated =
signIn.firstFactorVerification.status === 'transferable';
if (userNeedsToBeCreated) {
const res = await signUp.create({
transfer: true,
});
if (res.status === 'complete') {
setActive({
session: res.createdSessionId,
});
}
} else {
// If the user has an account in your application
// and has an OAuth account connected to it, you can sign them in.
signInWith(strategy);
}
}
// Render a button for each supported OAuth provider
// you want to add to your app. This example uses only Google.
return (
<div>
<button onClick={() => handleSignIn('oauth_google')}>
Sign in with Google
</button>
</div>
);
}