Blog-Post-Header-ImagePasskeys Implementation

FastAPI Passkeys: How to Implement Passkeys with FastAPI

In this tutorial, we show you how to integrate passkeys into a Python FastAPI web app using Corbado’s passkey-first web-js library.

Blog-Post-Author

Nicolai

Created: December 19, 2023

Updated: September 3, 2024


We aim to make the Internet a safer place using passkeys. That's why we want to support developers with tutorials on how to implement passkeys.

Overview#

1. Introduction

In this tutorial, we will be walking through the process of building a sample application with passkey authentication using the FastAPI web framework made for Python. To make passkeys work, we use Corbado's passkey-first web-js package that automatically connects to a passkeys backend.

If you want to run the project straight away, please follow the README of our sample app Github repository.

The result looks as follows:

FastAPI Passkeys UI Component

2. FastAPI Passkey Project Prerequisites

This tutorial assumes basic familiarity with FastAPI and Python as well as HTML and JavaScript. Let's dive in!

Slack Icon

Become part of our Passkeys Community for updates and support.

Join

3. Repository Structure for FastAPI Passkey Project

Our FastAPI project contains many files, but these are the most important ones:

├── .env                 # Contains all environment variables ├── main.py              # Contains our webapplication (Handles routes) └── templates ├── index.html       # Login page └── profile.html     # Profile page

4. Set Up Your Corbado Account and Project

Visit the Corbado developer panel to sign up and create your account (you'll see the passkey sign-up in action here!).

Corbado Developer Panel FastAPI

After sign-up, a project wizard will guide you through the necessary steps to get everything up and running:

  1. Begin by selecting an appropriate name for your project.
  2. For the product selection, opt for "Corbado Complete".
  3. Register your community license and optionally join our Passkeys Community or subscribe to the Passkeys Substack.
  4. Select "DEV" as your environment.
  5. Choose "Corbado session management" to get secure and efficient session management besides passkey authentication.
  6. Choose "Web app" as we're building a web application.
  7. Select "Vanilla JS" as your frontend framework.
  8. Provide the Application URL and Relying Party ID. The Application URL is the URL where you embed the Corbado UI component. In this example, we set it to http://localhost:8000. The Relying Party ID is the domain (no protocol, no port, and no path) where passkeys should be bound. Here, it's localhost (you can define both values als in the Settings > General > URLs of the Corbado developer panel).

Afterwards, you'll see the relevant HTML / JavaScript code snippets you need to integrate into the project. The subsequent sections of this article will explain them in detail.

As another step, we create an API secret which will be needed to request user data from the Corbado backend. Please create an API secret in Settings > Credentials > API secrets.

Corbado Developer Panel: Create API Secret

5. FastAPI Passkey Project Setup

5.1 Initialize Project

If you haven't installed FastAPI yet, do so by executing

pip install fastapi

To initialize our project, we simply create a main.py file with the following content:

from fastapi import FastAPI, Request, HTTPException from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles import requests import os app = FastAPI() if __name__ == "__main__":     import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)

5.2 Configure Environment Variables

We create a .env file in the root folder with the following contents (using your values of course):

PROJECT_ID=pro-xxx API_SECRET=corbado1_xxx

We use python-dotenv to load the variables. Install it by running

pip install python-dotenv

Then, we can import it into our main.py file and use it to obtain the variables from our .env file:

from fastapi import FastAPI, Request, HTTPException from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles import requests from dotenv import load_dotenv import os load_dotenv() app = FastAPI() PROJECT_ID = os.getenv("PROJECT_ID", "pro-xxx") API_SECRET = os.getenv("API_SECRET", "corbado1_xxx") if __name__ == "__main__":     import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)

5.3 Create Templates with Session Management

For our templates, we create a templates folder. The login page will be in templates/login.html. It contains a script from Corbado with styles as well as the logic needed to display the authentication component. See more info on how to use web-js here

<!DOCTYPE html> <html>   <head>     <link       rel="stylesheet"       href="https://unpkg.com/@corbado/web-js@latest/dist/bundle/index.css"     />     <script src="https://unpkg.com/@corbado/web-js@latest/dist/bundle/index.js"></script>   </head>     <body>     <script> (async () => {         await Corbado.load({           projectId: "{{ PROJECT_ID }}",           darkMode: "off",           setShortSessionCookie: "true", //set short session cookie automatically });         const authElement = document.getElementById('corbado-auth'); //Element where you want to render CorbadoAuth UI         Corbado.mountAuthUI(authElement, {           onLoggedIn: () => {             //post login actions can be performed here.             window.location.href = '/profile'; }, }); })();     </script>         <div id="corbado-auth"></div>   </body> </html>

Our second page is the profile page which the user will be redirected to after authentication. Here, we show some basic user info which we will obtain in the Python controller beforehand (we will create it later). We also provide a logout button that will terminate the session Corbado had initiated after authentication. The page is located at templates/profile.html with the following content:

<!DOCTYPE html> <html>   <head>     <link       rel="stylesheet"       href="https://unpkg.com/@corbado/web-js@latest/dist/bundle/index.css"       />       <script src="https://unpkg.com/@corbado/web-js@latest/dist/bundle/index.js"></script>     </head>     <body>             <!-- Define passkey-list div and logout button -->     <h2>:/protected 🔒</h2>     <p>User ID: {{USER_ID}}</p>     <p>Name: {{USER_NAME}}</p>     <p>Email: {{USER_EMAIL}}</p>     <div id="passkey-list"></div>     <button id="logoutButton">Logout</button>     <!-- Script to load Corbado and mount PasskeyList UI -->     <script> (async () => {             await Corbado.load({                 projectId: "{{ PROJECT_ID }}",                 darkMode: "off",                 setShortSessionCookie: "true" // set short session cookie automatically });                         // Get and mount PasskeyList UI             const passkeyListElement = document.getElementById("passkey-list"); // Element where you want to render PasskeyList UI             Corbado.mountPasskeyListUI(passkeyListElement);             // Get the logout button             const logoutButton = document.getElementById('logoutButton');             // Add event listener to logout button logoutButton.addEventListener('click', function() {               Corbado.logout() .then(() => {                         window.location.replace("/"); }) .catch(err => {                         console.error(err); }); }); })();     </script>     </body> </html>

5.4 Create FastAPI Controller

Since we only build a comparatively small app, our controller will be placed in our main.py file. Therefore, it will hold the entire web app logic comprised of two methods one for the index page and one for the profile page. Inside the index method, we only need to inject the project ID, but inside the profile method, we need to verify the integrity of the Corbado session and extract the data stored in it. For this, we use the Corbado Python SDK (passkeys):

pip install passkeys

The main.py file should look like this afterwards:

main.py
from typing import List from corbado_python_sdk.entities.session_validation_result import ( SessionValidationResult, ) from corbado_python_sdk.generated.models.identifier import Identifier from fastapi import FastAPI, Request, Response from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from dotenv import load_dotenv import os from corbado_python_sdk import ( Config, CorbadoSDK, IdentifierInterface, SessionInterface, ) load_dotenv() app = FastAPI() templates = Jinja2Templates(directory="templates") PROJECT_ID: str = os.getenv("PROJECT_ID", "pro-xxx") API_SECRET: str = os.getenv("API_SECRET", "corbado1_xxx") # Session config short_session_cookie_name = "cbo_short_session" # Config has a default values for 'short_session_cookie_name' and 'BACKEND_API' config: Config = Config( api_secret=API_SECRET, project_id=PROJECT_ID, ) # Initialize SDK sdk: CorbadoSDK = CorbadoSDK(config=config) sessions: SessionInterface = sdk.sessions identifiers: IdentifierInterface = sdk.identifiers @app.get("/", response_class=HTMLResponse) async def get_login(request: Request): return templates.TemplateResponse( "login.html", {"request": request, "PROJECT_ID": PROJECT_ID} ) @app.get("/profile", response_class=HTMLResponse) async def get_profile(request: Request): # Acquire cookies with your preferred method token: str = request.cookies.get(config.short_session_cookie_name) or "" validation_result: SessionValidationResult = ( sessions.get_and_validate_short_session_value(short_session=token) ) if validation_result.authenticated: emailList: List[Identifier] = identifiers.list_all_emails_by_user_id( user_id=validation_result.user_id or "" # at this point user_id should be non empty string since user was authenticated ) context = { "request": request, "PROJECT_ID": PROJECT_ID, "USER_ID": validation_result.user_id, "USER_NAME": validation_result.full_name, "USER_EMAIL": emailList[0].value, } return templates.TemplateResponse("profile.html", context) else: return Response( content="You are not authenticated or have not yet confirmed your email.", status_code=401, ) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)

6. Run FastAPI Application

Substack Icon

Subscribe to our Passkeys Substack for the latest news, insights and strategies.

Subscribe

To run your FastAPI application, you need to install uvicorn:

pip install 'uvicorn[standard]'

Afterwards, use the following command:

uvicorn main:app --reload

Your FastAPI application will start when visiting http://localhost:8000 with a web browser. You should see the Authentication UI.

FastAPI Passkeys UI Component

After successful sign up / login, you see the profile page:

FastAPI Passskey List

7. Conclusion

This tutorial showed how easy it is to add passwordless authentication with passkeys to a FastAPI app with using Corbado. Besides the passkey-first authentication, Corbado provides simple session management, that we used for a retrieval of basic user data. If you want to read more about how Corbado's session management please check the docs here. If you want to add Corbado to your existing app with existing users, please see our documentation here.

Share this article


LinkedInTwitterFacebook

Table of Contents

Enjoyed this read?

🤝 Join our Passkeys Community

Share passkeys implementation tips and get support to free the world from passwords.

🚀 Subscribe to Substack

Get the latest news, strategies, and insights about passkeys sent straight to your inbox.


We provide UI components, SDKs and guides to help you add passkeys to your app in <1 hour

Start for free