Docs

Build a custom sign-out flow

Warning

This guide is for users who want to build a custom user interface using the Clerk API. To use a prebuilt UI, you should use Clerk's Account Portal pages or prebuilt components.

Clerk's <UserButton /> and <SignOutButton /> components provide an out-of-the-box solution for signing out users. However, if you're building a custom solution, you can use the signOut() function to handle the sign-out process.

The signOut() function signs a user out of all sessions in a multi-session application, or only the current session in a single-session context. You can also specify a specific session to sign out by passing the sessionId parameter.

Note

The sign-out flow deactivates only the current session. Other valid sessions associated with the same user (e.g., if the user is signed in on another device) will remain active.

The useClerk() hook is used to access the signOut() function, which is called when the user clicks the sign-out button.

The Next.js useRouter() hook is used to redirect the user to the home page after they sign out.

This example is written for Next.js App Router but can be adapted for any React meta framework, such as Remix.

/app/components/SignOutButton.tsx
'use client'

import { useClerk } from '@clerk/nextjs'

export const SignOutButton = () => {
  const { signOut } = useClerk()

  return (
    // Clicking this button signs out a user
    // and redirects them to the home page "/".
    <button onClick={() => signOut({ redirectUrl: '/' })}>Sign out</button>
  )
}

Use the following tabs to view the code necessary for each file.

index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/clerk.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Clerk + JavaScript App</title>
  </head>

  <body>
    <div id="app"></div>
    <button id="sign-out">Sign out</button>
    <script type="module" src="main.js" async crossorigin="anonymous"></script>
  </body>
</html>
main.js
import Clerk from '@clerk/clerk-js'

// Initialize Clerk with your Clerk publishable key
const clerk = new Clerk('YOUR_PUBLISHABLE_KEY')
await clerk.load()

if (clerk.user) {
  // Attach signOut function to the sign-out button
  document.getElementById('sign-out').addEventListener('click', async () => {
    await clerk.signOut()
    // Optional: refresh page after sign-out
    window.location.reload()
  })
}
index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/clerk.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Clerk + JavaScript App</title>
  </head>

  <body>
    <div id="app"></div>
    <button id="sign-out">Sign out</button>

    <!-- Clerk's JavaScript SDK -->
    <script
      async
      crossorigin="anonymous"
      data-clerk-publishable-key="YOUR_PUBLISHABLE_KEY"
      src="https://YOUR_FRONTEND_API_URL/npm/@clerk/clerk-js@latest/dist/clerk.browser.js"
      type="text/javascript"
    ></script>

    <!-- Your custom sign-out button -->
    <script>
      window.addEventListener('load', async function () {
        await Clerk.load()

        if (Clerk.user) {
          document.getElementById('sign-out').addEventListener('click', async function () {
            await Clerk.signOut()
            // Optional: refresh page after sign-out
            window.location.reload()
          })
        }
      })
    </script>
  </body>
</html>
SignOutView.swift
import SwiftUI
import ClerkSDK

struct SignOutView: View {
  @ObservedObject private var clerk = Clerk.shared

  var body: some View {
    if let session = clerk.session {
      Text("Active Session: \(session.id)")
      Button("Sign out") {
        Task { await signOut() }
      }
    } else {
      Text("You are signed out")
    }
  }
}

extension SignOutView {

  func signOut() async {
    do {
      try await clerk.signOut()
    } catch {
      // See https://clerk.com/docs/custom-flows/error-handling
      // for more info on error handling.
      dump(error)
    }
  }
}

Feedback

What did you think of this content?

Last updated on