---
url: 'https://www.corbado.com/blog/passkeys-python-flask'
title: 'Flask Passkeys: How to Implement Passkeys with Python Flask'
description: 'Passkeys in Python Flask: Secure your Flask applications with passkeys by following this tutorial for Python Flask developers.'
lang: 'en'
author: 'Janina'
date: '2023-09-15T00:00:00.000Z'
lastModified: '2026-03-25T10:00:13.937Z'
keywords: 'Flask'
category: 'Passkeys Implementation'
---

# Flask Passkeys: How to Implement Passkeys with Python Flask

## Overview

Passkeys are emerging as a passwordless and more secure way to log into websites. In this
tutorial, we will learn how to use the Corbado UI components to implement
[passkey login](https://www.corbado.com/blog/passkey-login-best-practices) functionality for a great user
experience. Using Python and the Flask framework, we will build a login page that accepts
passkeys to authenticate users. With just a few lines of code, you can add this
cutting-edge login method to enable fast, simple, and secure access to your web app.

## 1. What we will build

The image below provides a preview of the
[passkey login](https://www.corbado.com/blog/passkey-login-best-practices) page we will create by following the
step-by-step instructions in this tutorial:

![flask passkeys ui component](https://www.corbado.com/website-assets/flask_passkeys_ui_component_7193bd2149.png)

## 2. Python passkey project prerequisites

This tutorial is suitable for both beginners and experienced developers. To follow along,
you'll need to have the following:

- Have Python and `pip` installed
- Basic knowledge of HTML, JavaScript, Python, and Flask - though you can still follow
  along even if you're new to these.

## 3. Repository structure for Python passkey project

For reference, the code snippet below outlines the directory structure of the Flask
passkey app we will be coding in this tutorial. You can grab the full source code for the
complete project from this
[GitHub URL](https://github.com/corbado/example-passkeys-python-flask). Copy the
`.env.example` file and rename it to `.env`.

```txt
/FLASK-CORBADO
    /templates
        login.html
        home.html
    .env
    corbado-auth.py
```

**Explanation:**

- `/templates`: This folder will contain the HTML templates for your login and home pages.
- `.env`: This file will securely store the Corbado project ID.
- `corbado-auth.py`: This is the main file where your Flask application will be defined.

## 4. Flask project setup

Follow the steps below to set up your project:

1. Create your project directory, here:

```bash
mkdir example-passkeys-python-flask-main
```

```bash
cd example-passkeys-python-flask-main
```

2. Verify if `pip` is installed by running:

```bash
pip --version
```

3. Finally, let's install the required packages, we will use `pip` to install Flask,
   python-dotenv, Corbado [Python SDK](https://www.corbado.com/blog/how-to-build-python-sdk-openapi) (which is
   called `passkeys` within `pip`):

```bash
pip install flask python-dotenv passkeys
```

This will install:

- Flask - A lightweight WSGI web application framework for Python
- python-dotenv - For loading environment variables from a .env file
- passkeys - Corbado SDK that provides straightforward access to Corbado services

## 5. Configure Corbado for Passkey Authentication

## 5.1 Set Up Your Corbado Account and Project

Visit the
[Corbado developer panel](https://app.corbado.com/signin?technology=passkeys&framework=Flask#register)
to sign up and create your account (you'll see the passkey sign-up in action here!).

![Corbado Developer Panel Flask](https://www.corbado.com/website-assets/corbado_developer_panel_flask_692d3b15cb.png)

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](https://bit.ly/passkeys-community) or subscribe to the
   [Passkeys Substack](https://passkeys.substack.com/).
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:5000`. 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](https://app.corbado.com/app/settings/general/urls) of the
   Corbado developer panel).

Afterwards, you will 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](https://app.corbado.com/app/settings/credentials/api-keys).

![Corbado Developer Panel: Create API Secret](https://www.corbado.com/website-assets/64a56b814cbf454723ef25e6_api_secret_1e55e98444.png)

### 5.2 Configure environment variables

In the `.env` file, you will store sensitive credentials like your API secret and project
ID as environment variables. This is a security best practice to avoid hardcoding these
values directly in your scripts. To get your API secret and project ID, visit your
[Corbado developer panel](https://app.corbado.com/).

Please refer to the [Corbado docs](https://docs.corbado.com/overview/welcome) for more
details on obtaining the necessary credentials and integrating Corbado authentication in
your application.

```txt filename=".env"
API_SECRET=enter_api_key
PROJECT_ID=enter_project_id
```

### 5.3 Create Flask routes and load environment variables

Create the `corbado-auth.py` file, which holds our Flask app that integrates with Corbado
for authentication. In this code, we loaded credentials from environment variables using
`python-dotenv`. A `Session` class validates JWTs from cookies to determine the current
user. The `/` route displays a login page, while `/home` shows the user's profile if
authenticated, else raises `Unauthorized`.

Routes are protected by validating JWTs which are short-lived. JWT signatures are verified
using public keys from a JWKS URI. The `Session` class handles JWT validation and
protected routes grant access only to valid users. We use `Corbado Python SDK` (passkeys)
to handle the session.

```python filename="corbado-auth.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 flask import Flask, render_template, request
from werkzeug.exceptions import Unauthorized
from dotenv import load_dotenv
import os
from corbado_python_sdk import (
    Config,
    CorbadoSDK,
    IdentifierInterface,
    UserEntity,
    SessionInterface,
    UserInterface,
)

# Load environment variables from the .env file
load_dotenv()

app = Flask(__name__)

PROJECT_ID: str = os.environ.get("PROJECT_ID") or ""
API_SECRET: str = os.environ.get("API_SECRET") or ""

# 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
users: UserInterface = sdk.users

# Use the API_SECRET from the environment variables
app.config["API_SECRET"] = API_SECRET

# Pass PROJECT_ID as a context variable to templates
app.config["PROJECT_ID"] = PROJECT_ID

@app.route("/")
def login() -> str:
    return render_template(
        template_name_or_list="login.html", PROJECT_ID=app.config["PROJECT_ID"]
    )

@app.route("/home")
def home() -> str:
    # Acquire cookies with your preferred method
    token: str = request.cookies.get(config.short_session_cookie_name) or ""
   validation_result: SessionValidationResult = sessions.get_current_user(
        short_session=token
    )

    if validation_result.authenticated:
        user: UserEntity = users.get(user_id=validation_result.user_id)
        email_identifiers: List[Identifier] = identifiers.list_all_emails_by_user_id(
            user_id=validation_result.user_id
        )

        user_data = {
            "id": user.user_id,
            "name": user.full_name,
            "email": email_identifiers[0].value,
        }
        return render_template(
            template_name_or_list="home.html",
            user_data=user_data,
            PROJECT_ID=app.config["PROJECT_ID"],
        )
    else:
         raise Unauthorized()

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

```

### 5.4 Create templates with session management

Now, create HTML templates for the login and home pages. The project ID will be
dynamically inserted into these templates using the `Jinja2` template engine, which is
integrated with Flask.

#### 5.4.1 Login Page (login.html)

Copy and paste these codes in the `templates/login.html` file to create the login page
using the Corbado UI component:

```html filename="templates/login.html"
<!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>

  <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 = '/home';
          },
        });
      })();
    </script>

    <div id="corbado-auth"></div>
  </body>
</html>

```

#### 5.4.2 Home Page (home.html)

Now, we create our protected home page, visible only after user authentication and
validation. It showcases user details and incorporates the `Corbado Python SDK` (passkeys)
for authentication, allowing users to log out with a simple button click.

```html filename="templates/home.html"
<!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 -->
        ## :/protected 🔒
        <p>User ID: {{ user_data.id }}</p>
        <p>Name: {{ user_data.name }}</p>
        <p>Email: {{ user_data.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>
```

In both templates, the `PROJECT_ID` is dynamically inserted using `{{ PROJECT_ID }}` to
include the project ID from the environment variables.

### 5.5 Run the Flask application

Now, run your Flask application using the following command in the terminal:

```bash
python corbado-auth.py
```

![flask passkeys ui component](https://www.corbado.com/website-assets/flask_passkeys_ui_component_7193bd2149.png)

Your Flask application will start, and you can open a web browser to visit
[http://localhost:5000](http://localhost:5000) to see your login page.

![flask passkey list](https://www.corbado.com/website-assets/flask_passkey_list_9e4e07480f.png)

After a successful login and session validation, you should be redirected to the home page
where you can see some user data and the logout button as shown in the image above.

## 6. Conclusion

Implementing passkey authentication creates a seamless and secure login experience for
users, removing the [vulnerabilities](https://www.corbado.com/glossary/vulnerability) of passwords. This tutorial
showed how to easily integrate passkeys into a Flask app using Corbado.

With just a few lines of Python code, we built a login page that accepts passkeys for
authentication. Passkeys represent are the new standard of login, eliminating
[phishing](https://www.corbado.com/glossary/phishing) and breaches tied to reused passwords. By following this
guide, you can add cutting-edge passkey support to your own Flask apps and take a step
towards a passwordless web.

## Frequently Asked Questions

### How do I protect routes in a Flask passkey application?

Routes are protected by reading a short-session cookie and validating the JWT it contains
using public keys from a JWKS URI. The Corbado Session class handles this validation, and
only requests with authenticated tokens are granted access to protected routes like the
home page.

### What is the difference between the Application URL and the Relying Party ID when setting up passkeys in Flask?

The Application URL is the full URL where the Corbado UI component is embedded, for
example [http://localhost:5000](http://localhost:5000). The
[Relying Party](https://www.corbado.com/glossary/relying-party) ID is the bare domain with no protocol, port or
path, for example 'localhost', and it defines where passkeys are cryptographically bound.

### How does the Corbado UI component render the passkey login interface in a Flask template?

The Corbado UI component is loaded via a JavaScript bundle referenced in the HTML head,
then mounted to a designated div element using Corbado.mountAuthUI(). An onLoggedIn
callback handles post-authentication redirects, and setting setShortSessionCookie to true
ensures the session cookie is created automatically.

### How do I retrieve user details after a successful passkey login in a Flask app using Corbado?

After validating the session JWT, use the Corbado SDK's users.get() method with the
validated [user ID](https://www.corbado.com/blog/webauthn-user-id-userhandle) to retrieve the UserEntity. You can
then call identifiers.list_all_emails_by_user_id() to fetch the user's email identifiers
and pass all data to your Jinja2 template for rendering.
