SAML Connections
Custom flow
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 by following this link to your Enterprise Connections.
When using SAML, the sign in and sign up are equivalent. A successful SAML 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 Identity Provider. - Create a route at the URL
redirectUrl
points, typically/sso-callback
, that calls theClerk.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.
1import React from "react";2import {3BrowserRouter,4Switch,5Route,6} from "react-router-dom";7import { SamlStrategy } from "@clerk/types";8import {9ClerkProvider,10ClerkLoaded,11AuthenticateWithRedirectCallback,12UserButton,13useSignIn,14SignedIn,15SignedOut16} from "@clerk/clerk-react";1718function App() {19return (20// react-router-dom requires your app to be wrapped with a Router21<BrowserRouter>22<ClerkProvider frontendApi="{{fapi}}">23<Switch>24{/* Define a / route that displays the OAuth buttons */}25<Route path="/">26<SignedOut>27<SignInSAMLButton />28</SignedOut>29<SignedIn>30<UserButton afterSignOutAllUrl="/" />31</SignedIn>32</Route>3334{/* Define a /sso-callback route that handles the SAML redirect flow from the IdP */}35<Route path="/sso-callback">36<SSOCallback />37</Route>38</Switch>39</ClerkProvider>40</BrowserRouter>41);42}4344function SSOCallback() {45// Handle the redirect flow by rendering the46// prebuilt AuthenticateWithRedirectCallback component.47// This is the final step in the custom SAML flow48return <AuthenticateWithRedirectCallback />;49}5051function SignInSAMLButton() {52const { signIn } = useSignIn();5354const signInWith = (strategy: SamlStrategy) => {55return signIn.authenticateWithRedirect({56identifier: "email_goes_here",57strategy: strategy,58redirectUrl: "/sso-callback",59redirectUrlComplete: "/",60});61};6263// Render a button for each supported SAML provider64// you want to add to your app65return (66<div>67<button onClick={() => signInWith("saml")}>68Sign in with SAML69</button>70</div>71);72}7374export 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.
1user2.createExternalAccount({ strategy: strategy, redirect_url: 'your-redirect-url' })3.then(externalAccount => {4// navigate to5// externalAccount.verification!.externalVerificationRedirectURL6})7.catch(err => {8// handle error9});
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.”
1// Get sign-in and sign-up objects in the SAML callback page2const { signIn, signUp } = window.Clerk.client;34// If the user has an account in your application, but does not yet5// have a saml account connected, you can use the transfer method to6// forward that information.78const userExistsButNeedsToSignIn =9signUp.verifications.externalAccount.status === "transferable" &&10signUp.verifications.externalAccount.error?.code ===11"external_account_exists";1213if (userExistsButNeedsToSignIn) {14const res = await signIn.create({ transfer: true });15if (res.status === "complete") {16window.Clerk.setActive({17session: res.createdSessionId,18});19}20}2122// If the user has an existing saml account but does not yet exist as23// a user in your app, you can use the transfer method to forward that24// information.2526const userNeedsToBeCreated =27signIn.firstFactorVerification.status === "transferable";2829if (userNeedsToBeCreated) {30const res = await signUp.create({31transfer: true,32});33if (res.status === "complete") {34window.Clerk.setActive({35session: res.createdSessionId,36});37}38}