Easy to use authentication platform designed to provide a flexible, secure, and fast integration.
Quickly integrate AuthKit in your project with the AI-powered WorkOS CLI.
npx workos@latest
In this guide, you’ll add a complete hosted authentication flow to your application using AuthKit. By the end, you’ll have signup, sign-in, and session management working end-to-end.
For additional implementation patterns, see the example apps.
Make sure you have:
Activate AuthKit in your WorkOS Dashboard if you haven’t already. In the Overview section, click the Set up AuthKit button and follow the instructions.

A redirect URI is a callback endpoint that WorkOS redirects to after a user has authenticated. This endpoint exchanges the authorization code returned by WorkOS for an authenticated User object.
Set a redirect URI in the Redirects section of the WorkOS Dashboard. Use http://localhost:3000/callback as the default.
WorkOS supports using wildcard characters in Redirect URIs, but not for the default Redirect URI. More information about wildcard characters support can be found in the Redirect URIs guide.

When users sign out of their application, they will be redirected to your app’s Sign-out redirect location which is configured in the same dashboard area.
Sign-in requests should originate from your application. In some instances, requests may not begin at your app. For example, some users might bookmark the hosted sign-in page or they might be led directly to the hosted sign-in page when clicking on a password reset link in an email.
In these cases, AuthKit detects when a sign-in request did not originate at your application and redirects to your application’s sign-in endpoint. This is an endpoint that you define at your application that redirects users to sign in using AuthKit.
Configure the sign-in endpoint from the Redirects section of the WorkOS dashboard.

To make calls to WorkOS, provide the API key and the client ID. Store these values as managed secrets and pass them to the SDKs either as environment variables or directly in your app’s configuration depending on your preferences.
WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789'
The code examples use your staging API keys when signed in
To demonstrate AuthKit, we only need a simple page with links to logging in and out.
export default function App() { return ( <div className="App"> <h1>AuthKit example</h1> <p>This is an example of how to use AuthKit with a React frontend.</p> <p> <a href="/login">Sign in</a> </p> <p> <a href="/logout">Sign out</a> </p> </div> ); }
Clicking the “Sign in” and “Sign out” links should invoke actions on our server, which we’ll set up next.
Create a sign-in endpoint to direct users to sign in (or sign up) using AuthKit before redirecting them back to your application. This endpoint generates an AuthKit authorization URL server side and redirects the user to it.
Use the optional state parameter to encode arbitrary information to help restore application state between redirects.
This guide uses the flask web server for Python. For more information on setting up Flask, see the Flask documentation.
import os from dotenv import load_dotenv from flask import Flask, redirect, send_file from workos import WorkOSClient load_dotenv() app = Flask(__name__) workos = WorkOSClient( api_key=os.getenv("WORKOS_API_KEY"), client_id=os.getenv("WORKOS_CLIENT_ID") ) @app.route("/") def index(): return send_file("index.html") @app.route("/login") def login(): authorization_url = workos.user_management.get_authorization_url( provider="authkit", redirect_uri="http://localhost:3000/callback" ) return redirect(authorization_url) if __name__ == "__main__": app.run(debug=True, port=3000)
WorkOS will redirect to your Redirect URI if there is an issue generating an authorization URL. Read our API Reference for more details.
Next, add the callback endpoint (referenced in Configure a redirect URI) to exchange the authorization code (valid for 10 minutes) for an authenticated User object.
import os from dotenv import load_dotenv from flask import Flask, make_response, redirect, request, url_for from workos import WorkOSClient load_dotenv() app = Flask(__name__) workos = WorkOSClient( api_key=os.getenv("WORKOS_API_KEY"), client_id=os.getenv("WORKOS_CLIENT_ID") ) cookie_password = os.getenv("WORKOS_COOKIE_PASSWORD") @app.route("/login") def login(): authorization_url = workos.user_management.get_authorization_url( provider="authkit", redirect_uri="http://localhost:3000/callback" ) return redirect(authorization_url) @app.route("/callback") def callback(): code = request.args.get("code") try: auth_response = workos.user_management.authenticate_with_code( code=code, ) # Use the information in auth_response for further business logic. response = make_response(redirect("/")) return response except Exception as e: print("Error authenticating with code", e) return redirect(url_for("login")) if __name__ == "__main__": app.run(debug=True, port=3000)
Session management helper methods are included in our SDKs to make integration easy. For security reasons, sessions are automatically “sealed”, meaning they are encrypted with a strong password.
The SDK requires you to set a strong password to encrypt cookies. This password must be 32 characters long. You can generate a secure password by using the 1Password generator or the openssl library via the command line:
openssl rand -base64 32
Add it to the environment variables file.
WORKOS_API_KEY='sk_example_123456789' WORKOS_CLIENT_ID='client_123456789' WORKOS_COOKIE_PASSWORD='<your password>'
Use the SDK to authenticate the user and return a password-protected session. The refresh token is considered sensitive as it can be used to re-authenticate, so encrypt the session before storing it in a session cookie.
import os from dotenv import load_dotenv from flask import Flask, make_response, redirect, request, url_for from workos import WorkOSClient load_dotenv() app = Flask(__name__) workos = WorkOSClient( api_key=os.getenv("WORKOS_API_KEY"), client_id=os.getenv("WORKOS_CLIENT_ID") ) cookie_password = os.getenv("WORKOS_COOKIE_PASSWORD") @app.route("/login") def login(): authorization_url = workos.user_management.get_authorization_url( provider="authkit", redirect_uri="http://localhost:3000/callback" ) return redirect(authorization_url) @app.route("/callback") def callback(): code = request.args.get("code") try: auth_response = workos.user_management.authenticate_with_code( code=code, session={"seal_session": True, "cookie_password": cookie_password}, ) response = make_response(redirect("/")) # store the session in a cookie response.set_cookie( "wos_session", auth_response.sealed_session, secure=True, httponly=True, samesite="lax", ) return response except Exception as e: print("Error authenticating with code", e) return redirect(url_for("login")) if __name__ == "__main__": app.run(debug=True, port=3000)
Present user information on the frontend. Update the default route to read the session cookie and display user information:
@app.route("/") def index(): user_data = "" sealed_session = request.cookies.get("wos_session") if sealed_session: try: session = workos.user_management.load_sealed_session( sealed_session=sealed_session, cookie_password=cookie_password, ) auth_response = session.authenticate() if auth_response.authenticated and auth_response.user: user = auth_response.user user_data = f"Welcome, {user.first_name or ''} {user.last_name or ''}! ({user.email or ''})" except Exception: pass with open("index.html") as f: html = f.read() return html.replace("{{USER_DATA}}", user_data)
Update the index page to present this info.
<!doctype html> <html lang="en"> <head> <title>AuthKit example</title> </head> <body> <h1>AuthKit example</h1> {{USER_DATA}} <p>This is an example of how to use AuthKit with an HTML frontend.</p> <p> <a href="/login">Sign in</a> </p> <p> <a href="/logout">Sign out</a> </p> </body> </html>
Use a decorator to specify which routes should be protected. If the session has expired, use the SDK to attempt to generate a new one.
from dotenv import load_dotenv import os from functools import wraps from flask import Flask, redirect, request, make_response, url_for from workos import WorkOSClient load_dotenv() app = Flask(__name__) workos = WorkOSClient( api_key=os.getenv("WORKOS_API_KEY"), client_id=os.getenv("WORKOS_CLIENT_ID") ) cookie_password = os.getenv("WORKOS_COOKIE_PASSWORD") # Decorator to check if the user is authenticated. If not, redirect to login def with_auth(f): @wraps(f) def decorated_function(*args, **kwargs): session = workos.user_management.load_sealed_session( sealed_session=request.cookies.get("wos_session"), cookie_password=cookie_password, ) auth_response = session.authenticate() if auth_response.authenticated: return f(*args, **kwargs) if ( auth_response.authenticated is False and auth_response.reason == "no_session_cookie_provided" ): return make_response(redirect("/login")) # If no session, attempt a refresh try: print("Refreshing session") result = session.refresh() if result.authenticated is False: return make_response(redirect("/login")) response = make_response(redirect(request.url)) response.set_cookie( "wos_session", result.sealed_session, secure=True, httponly=True, samesite="lax", ) return response except Exception as e: print("Error refreshing session", e) response = make_response(redirect("/login")) response.delete_cookie("wos_session") return response return decorated_function @app.route("/login") def login(): authorization_url = workos.user_management.get_authorization_url( provider="authkit", redirect_uri="http://localhost:3000/callback" ) return redirect(authorization_url) @app.route("/callback") def callback(): code = request.args.get("code") try: auth_response = workos.user_management.authenticate_with_code( code=code, session={"seal_session": True, "cookie_password": cookie_password}, ) response = make_response(redirect("/")) # store the session in a cookie response.set_cookie( "wos_session", auth_response.sealed_session, secure=True, httponly=True, samesite="lax", ) return response except Exception as e: print("Error authenticating with code", e) return redirect(url_for("login")) if __name__ == "__main__": app.run(debug=True, port=3000)
Apply the decorator to the route that should only be accessible to logged-in users.
@app.route("/dashboard") @with_auth def dashboard(): session = workos.user_management.load_sealed_session( sealed_session=request.cookies.get("wos_session"), cookie_password=cookie_password, ) response = session.authenticate() current_user = response.user if response.authenticated else None print(f"User {current_user.first_name} is logged in") # Render a dashboard view
Finally, ensure the user can end their session by redirecting them to the logout URL. After successfully signing out, the user will be redirected to your app’s Sign-out redirect location, which is configured in the WorkOS dashboard.
@app.route("/logout") def logout(): session = workos.user_management.load_sealed_session( sealed_session=request.cookies.get("wos_session"), cookie_password=cookie_password, ) url = session.get_logout_url() # After log out has succeeded, the user will be redirected to your # app homepage which is configured in the WorkOS dashboard response = make_response(redirect(url)) response.delete_cookie("wos_session") return response
If you haven’t configured a Sign-out redirect in the WorkOS dashboard, users will see an error when logging out.
Start your server with python server.py, navigate to localhost:3000, and sign up for an account.
Sign in with the newly created credentials and verify the user appears in the Users section of the WorkOS Dashboard.
