Skip to Content
Clerk logo

Clerk Docs

Ctrl + K
Go to clerkstage.dev

SAML connections

In case our default SAML flow doesn’t cover your needs, you can leverage the Clerk SDK to build a completely custom SAML flow.

You still need to configure your instance through the Clerk Dashboard. You can create a SAML connection by visiting the Enterprise Connections(opens in a new tab) page.

When using SAML, the sign-in and sign-up are equivalent. A successful SAML flow consists of the following steps:

  1. Start the OAuth flow by calling SignIn.authenticateWithRedirect(params) or SignUp.authenticateWithRedirect(params). Note that both of these methods require a redirectUrl param, which is the URL that the browser will be redirected to once the user authenticates with the OAuth provider.
  2. Create a route at the URL redirectUrl points, typically /sso-callback, that calls the Clerk.handleRedirectCallback() or simply renders the prebuilt <AuthenticateWithRedirectCallback/> component.

The React example below uses react-router-dom to define the required route. For NextJS apps, you only need to create a pages/sso-callback file.

import React from "react"; import { BrowserRouter, Switch, Route, } from "react-router-dom"; import { SamlStrategy } from "@clerk/types"; import { ClerkProvider, ClerkLoaded, AuthenticateWithRedirectCallback, UserButton, useSignIn, SignedIn, SignedOut } from "@clerk/clerk-react"; const publishableKey = process.env.REACT_APP_CLERK_PUBLISHABLE_KEY; function App() { return ( // react-router-dom requires your app to be wrapped with a Router <BrowserRouter> <ClerkProvider publishableKey={publishableKey}> <Switch> {/* Define a / route that displays the OAuth buttons */} <Route path="/"> <SignedOut> <SignInSAMLButton /> </SignedOut> <SignedIn> <UserButton afterSignOutAllUrl="/" /> </SignedIn> </Route> {/* Define a /sso-callback route that handles the SAML redirect flow from the IdP */} <Route path="/sso-callback"> <SSOCallback /> </Route> </Switch> </ClerkProvider> </BrowserRouter> ); } function SSOCallback() { // Handle the redirect flow by rendering the // prebuilt AuthenticateWithRedirectCallback component. // This is the final step in the custom SAML flow return <AuthenticateWithRedirectCallback />; } function SignInSAMLButton() { const { signIn } = useSignIn(); const signInWith = (strategy: SamlStrategy) => { return signIn.authenticateWithRedirect({ identifier: "email_goes_here", strategy: strategy, redirectUrl: "/sso-callback", redirectUrlComplete: "/", }); }; // Render a button for each supported SAML provider // you want to add to your app return ( <div> <button onClick={() => signInWith("saml")}> Sign in with SAML </button> </div> ); } export default App;

To initiate a SAMLflow for a user that is already signed in, you can use the user.createExternalAccount(params) method, where user is a reference to the currently signed in user.

user .createExternalAccount({ strategy: strategy, redirect_url: 'your-redirect-url' }) .then(externalAccount => { // navigate to // externalAccount.verification!.externalVerificationRedirectURL }) .catch(err => { // handle error });

SAML account transfer flow

When a user initiates a SAML SSO verification during sign-in, or sign-up, it may sometimes be necessary to move the verification between the two flows.

For example, if someone already has an account, and tries to go through the sign up flow with the same SAML account, they can’t perform a successful sign up again. Or, if someone attempts to sign in with their SAML credentials but does not yet have an account, they won’t be signed in to the account. For these scenarios, we have “account transfers.”

// Get sign-in and sign-up objects in the SAML callback page const { signIn, signUp } = window.Clerk.client; // If the user has an account in your application, but does not yet // have a saml account connected, you can use the transfer method to // forward that information. 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") { window.Clerk.setActive({ session: res.createdSessionId, }); } } // If the user has an existing saml account but does not yet exist as // a user in your app, you can use the transfer method to forward that // information. const userNeedsToBeCreated = signIn.firstFactorVerification.status === "transferable"; if (userNeedsToBeCreated) { const res = await signUp.create({ transfer: true, }); if (res.status === "complete") { window.Clerk.setActive({ session: res.createdSessionId, }); } }

What did you think of this content?

Clerk © 2024