Explore our guide on database schemas for passkey/WebAuthn apps featuring user & credential table best practices for MySQL, PostgreSQL, SQLite & MongoDB.
Vincent
Created: March 26, 2024
Updated: February 17, 2025
Our mission is to make the Internet a safer place, and the new login standard passkeys provides a superior solution to achieve that. That's why we want to help you understanding passkeys and its characteristics better.
1. Introduction: Database Schema Recommendations for Passkeys
2. What's Complex about Database Schemas for Passkeys?
2.1 Different WebAuthn Server Library Implementations
2.2 WebAuthn Standard Requires Diverse Data Formats
3. Recommended Database Schema for Passkeys
3.1 Required Tables and Columns
3.2 Relationships Between Tables
4. Recommendations for Different Database Technologies
4.1 Passkey Schemas for Relational Databases
4.1.1.1 MySQL: Users Table Schema
4.1.1.2 MySQL: WebAuthn Credentials Table Schema
4.1.2.1 PostgreSQL: Users Table Schema
4.1.2.2 PosgreSQL: WebAuthn Credentials Table Schema
4.1.4 Passkeys in Microsoft SQL Server
4.1.5.1 SQLite: Users Table Schema
4.1.5.2 SQLite: WebAuthn Credentials Table Schema
4.2 Passkey Schemes for NoSQL Databases
4.2.1.1 MongoDB: Users Collection Structure
The implementation of WebAuthn and passkeys into applications promises enhanced security and a user-friendly alternative to traditional password- based logins. At the heart of a successful WebAuthn- / passkey-based application lie several components. Among these, the database has a central position, serving as the repository for all crucial data related to users, their devices, and the credentials.
Surprisingly, an analysis of provided passkey documentation and tutorials reveals a gap in the available resources for developers to define passkey database schemas correctly. While numerous tutorials offer guidance on setting up passkeys, many either assume the use of a passkey service, eliminating the need to think deeper over database schemas, or they present oversimplified recommendations, often limiting their advice to a single database technology.
Ben Gould
Head of Engineering
I’ve built hundreds of integrations in my time, including quite a few with identity providers and I’ve never been so impressed with a developer experience as I have been with Corbado.
10,000+ devs trust Corbado & make the Internet safer with passkeys. Got questions? We’ve written 150+ blog posts on passkeys.
Join Passkeys CommunityThe consequence of this reference gap is that developers have to dig deep into database documentations and combine it with the requirements outlined by the (already complex) WebAuthn specifications. Moreover, failing to properly design the database structure can lead to significant challenges down the road. Developers might find themselves fixing bugs about database fields or be lost in the encoding / decoding hell of WebAuthn (trust us, we also spent countless hours on these steps already).
That's why we recognized that coming up with a solid database structure is the foundational step for any passkey-based app. This guide aims provides recommendations for optimal passkey database schemas for the following database technologies (with the list continuously being updated and extended):
The complexity of setting up a proper database structure for passkey-based apps arises from some factors that developers must take care of.
First and foremost, the landscape of WebAuthn server libraries is diverse, with each library offering different approaches to integrating WebAuthn into a system. This diversity, while beneficial in providing options, complicates the process of determining the most appropriate database schema for your application. Each library may interact with the database in slightly different ways, requiring a nuanced understanding of both the library's inner workings and the database's capabilities.
In the following section, we provide an overview of some popular WebAuthn server libraries along with, where available, specific guides and documentation for them. Some WebAuthn server libraries clearly define the actual storage repository, while others leave the storage layer entirely up to the developer. It's important to note that these WebAuthn server libraries primarily specify the format of the credential table, but leave the specification of the user table to the developer.
WebAuthn Library | Language | Explicit Storage Repository | Storage Example |
---|---|---|---|
SimpleWebAuthn | Typescript | No | No |
fido2-net-lib | .NET | No | No |
py_webauthn | Python | No | No |
webauthn-ruby | Ruby | No | No |
go-webauthn | Golang | No | No |
java-webauthn-server | Java | Yes (CredentialRepository) | No |
webauthn-rs | Rust | No | No |
webauthn-framework | PHP | Yes | No |
Webauthn4j | Java | No | No |
Developers are frequently left to figure out the storage implementation on their own by the WebAuthn server library, with examples typically limited to in-memory code.
The WebAuthn standard itself specifies certain formats for data, such as cryptographic keys, challenge responses, and attestation objects. These formats are optimized for security and interoperability but present a challenge when it comes to storing them in a database. Different databases have different capabilities and limitations regarding data types and encoding, necessitating a careful approach to how data is encoded and stored. For example, storing binary data like public keys may be straightforward in one database but require a specialized binary data type or encoding in another.
While theoretically, any database could be used to store WebAuthn data, there's a strong preference within the developer community for using SQL and relational database management systems (RDBMS). The reasoning behind this preference lies in the transactional nature of WebAuthn operations, where the integrity and consistency of data are extremely important. Relational databases are great in maintaining transactional integrity, making them a favored choice.
However, this doesn't eliminate the potential for using NoSQL databases , which might be preferred for their scalability and flexibility in handling unstructured data. This choice adds another layer of complexity in deciding the right database system for your WebAuthn implementation.
Developers often encounter encoding issues when implementing WebAuthn, stemming from the need to store and retrieve complex data types. The correct encoding and decoding of data are crucial for the integrity and security of the authentication process. These challenges are not trivial; they require a deep understanding of both the WebAuthn protocol and the chosen database's handling of data types and encoding. One of the most commons misunderstandings we encountered is the difference between Base64 and Base64URL encodings.
We had to obtain our learnings also the hard way by going through cumbersome steps and research but can now provide firsthand experiences and lessons learned in developing passkey-based solutions.
The following content is not prescriptive but rather a starting point. It's designed to help developers with the knowledge to make informed decisions that align with the unique requirements of their WebAuthn implementations.
Below, we take a closer look into the components and considerations crucial for setting up a database that supports passkey authentication, focusing on the essential tables, their relationships, and the overarching security considerations.
To effectively manage passkey and WebAuthn data, a database should minimally include the following tables:
Optionally, the following tables can be added to the database to enhance the overall developer, debugging and user experience.
The relationships between tables are important for maintaining data integrity and facilitating database queries:
When designing your database for passkey authentication, you need to make sure that proper security measures are in place:
By carefully considering these aspects of database structure and security, developers can create a robust foundation for passkey authentication systems. This foundation not only supports the technical requirements of WebAuthn but also aligns with best practices for data security and privacy, ensuring a secure and user-friendly authentication experience for all users.
In the following, well provide recommendations for database schemes in different database technologies. As of March 2024, we provide recommendations for MySQL, PostgreSQL, SQLite and MongoDB(more database technologies will follow soon or are available upon request).
Relational databases, known for their robustness and adherence to ACID (Atomicity, Consistency, Isolation, Durability) properties, are highly recommended for managing passkey authentication data.
MySQL is an open-source relational database management system (RDBMS) that uses SQL for managing and manipulating relational databases. It's widely recognized for its reliability, efficiency, and ease of use.
MySQL supports a wide range of applications, from small to large enterprise applications, offering features such as transactional and non- transactional table types, robust data security, replication, and partitioning for scalability. It's highly favored in web applications and is a core component of the LAMP (Linux, Apache, MySQL, PHP/Perl/Python) stack, a popular open-source software stack used for web development.
For the users table in MySQL, we recommend the following database scheme:
CREATE TABLE users ( id INT NOT NULL AUTO_INCREMENT, userName VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(50), phoneNumber VARCHAR(25), displayName VARCHAR(25), registrationDate DATETIME DEFAULT CURRENT_TIMESTAMP, lastUpdatedDate DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, lastLoginDate DATETIME, PRIMARY KEY (id) );
For the credentials table in MySQL, we recommend the following database scheme:
CREATE TABLE credentials ( id INT NOT NULL AUTO_INCREMENT, userId INT NOT NULL, credentialId VARCHAR(1023) NOT NULL UNIQUE, publicKey TEXT, attestationType ENUM('direct', 'indirect', 'none') NOT NULL, AAGUID CHAR(36) DEFAULT '00000000-0000-0000-0000-000000000000', signatureCount INT, creationDate DATETIME DEFAULT CURRENT_TIMESTAMP, lastUsedDate DATETIME, lastUpdatedDate DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, type VARCHAR(25), transports SET('usb', 'nfc', 'ble', 'internal', ‘hybrid’), backupEligible BOOLEAN DEFAULT FALSE, backupState BOOLEAN DEFAULT FALSE, PRIMARY KEY (id), INDEX userId_index (userId), FOREIGN KEY (userId) REFERENCES user(id) ON DELETE CASCADE );
PostgreSQL is an advanced, open-source relational database management system (RDBMS) that emphasizes extensibility and SQL compliance. It offers a sophisticated data management system, supporting complex queries, foreign keys, triggers, views, transactional integrity, and multiversion concurrency control. PostgreSQL is highly respected for its proven architecture, reliability, data integrity, robust feature set, and its dedication to open standards and extensibility.
Widely adopted for a broad spectrum of applications, PostgreSQL is suitable for small projects as well as large, complex systems. It supports advanced data types, sophisticated locking mechanisms, and is well-suited for handling large volumes of data with mechanisms like table partitioning and replication. PostgreSQL is a key component of many software stacks and is often chosen for web applications, analytics, and geospatial databases. Its community-driven development model and its focus on performance, security, and compliance with the SQL standard make it a preferred choice for developers and enterprises alike.
For the users table in PostgreSQL, we recommend the following database scheme:
CREATE TABLE users ( id SERIAL PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, email VARCHAR(50), phone_number VARCHAR(25), display_name VARCHAR(25), registration_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, last_updated_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, last_login_date TIMESTAMP WITH TIME ZONE, CONSTRAINT users_pkey PRIMARY KEY (id) );
For the credentials table in PostgreSQL, we recommend the following database scheme:
CREATE TYPE attestation_type AS ENUM ('direct', 'indirect', 'none'); CREATE TABLE credentials ( id SERIAL, user_id INT NOT NULL, credential_id VARCHAR(1023) NOT NULL UNIQUE, public_key TEXT, attestation_type ENUM('direct', 'indirect', 'none') NOT NULL, aaguid CHAR(36) DEFAULT '00000000-0000-0000-0000-000000000000', signature_count INT, creation_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, last_used_date TIMESTAMP WITH TIME ZONE, last_updated_date TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, type VARCHAR(25), transports TEXT[], backup_eligible BOOLEAN DEFAULT FALSE, backup_state BOOLEAN DEFAULT FALSE, PRIMARY KEY (id), FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE );
Well soon provide more details regarding the recommended users and credentials table for Oracle. If you have urgent questions, feel free to reach out.
Well soon provide more details regarding the recommended users and credentials table for Microsoft SQL Server. If you have urgent questions, feel free to reach out.
SQLite is a renowned, open-source, serverless relational database management system (RDBMS) distinguished by its simplicity, portability, and efficient operation in a wide range of environments. Unlike traditional client-server database systems, SQLite is embedded into the end program, providing a self-contained, zero-configuration, transactional SQL database engine. This unique architecture makes it an ideal choice for devices with limited resources, mobile applications, application file formats, and temporary databases for testing or as a backend for prototype development.
SQLite supports most of the query language features found in SQL92 (SQL2) standard, including transactions, subqueries, views, and triggers. Despite its compact nature, it offers a robust set of features and can handle database sizes of up to 140 terabytes. SQLite is widely used in applications of all sizes, from small standalone applications to large web applications, thanks to its reliability, ease of use, and the fact that it requires no setup or administration, making it perfect for situations where simplicity and minimal overhead are critical.
For the users table in SQLite, we recommend the following database scheme:
CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT NOT NULL UNIQUE, email TEXT, phone_number TEXT, display_name TEXT, registration_date TEXT DEFAULT (datetime('now')), last_updated_date TEXT DEFAULT (datetime('now')), last_login_date TEXT );
For the credentials table in SQLite, we recommend the following database scheme:
CREATE TABLE credentials ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, credential_id TEXT NOT NULL UNIQUE, public_key TEXT, attestation_type TEXT NOT NULL, aaguid TEXT DEFAULT '00000000-0000-0000-0000-000000000000', signature_count INTEGER, creation_date TEXT DEFAULT (datetime('now')), last_used_date TEXT, last_updated_date TEXT DEFAULT (datetime('now')), type TEXT, transports TEXT, backup_eligible INTEGER DEFAULT 0, backup_state INTEGER DEFAULT 0, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE );
Well soon provide more details regarding the recommended users and credentials table forIBM DB2. If you have urgent questions, feel free to reach out.
Well soon provide more details regarding the recommended users and credentials table for MariaDB. If you have urgent questions, feel free to reach out.
In the following, we provide passkey table schemes for NoSQL databases.
MongoDB is a powerful, open-source, NoSQL database management system known for its flexibility, scalability, and performance. It uses a document-oriented approach, storing data in JSON-like documents with dynamic schemas (MongoDB calls this format BSON), enabling the integration of data in certain types of applications more easily and quickly than traditional RDBMS systems. MongoDB is designed to meet the demands of modern apps with a powerful query language, secondary indexes, and real-time aggregation.
It excels in handling large volumes of data and supports complex queries, full-text search, graph processing, and other advanced data manipulation. MongoDB's architecture features collections and documents instead of tables and rows, making it highly adaptable to changes in data structure. It is also well-suited for distributed data environments, offering out-of-the-box replication and sharding capabilities for high availability and horizontal scaling.
Widely adopted for building scalable web applications, MongoDB is a key component of the MEAN (MongoDB, Express.js, AngularJS, Node.js) or MERN (MongoDB, Express.js, React, Node.js) stack. MongoDB's document model maps naturally to object-oriented programming, making it particularly popular among developers working in agile environments that require rapid iteration and flexible data models.
For the users collection with schema validation in MongoDB, we recommend the following database scheme:
db.createCollection("users", { validator: { $jsonSchema: { bsonType: "object", required: ["username"], properties: { _id: { bsonType: "objectId" }, username: { bsonType: "string", uniqueItems: true }, email: { bsonType: "string" }, phone_number: { bsonType: "string" }, display_name: { bsonType: "string" }, registration_date: { bsonType: "date", default: "$$NOW" }, last_updated_date: { bsonType: "date", default: "$$NOW" }, last_login_date: { bsonType: "date" } } } } });
For the credentials collection with schema validation in MongoDB, we recommend the following database scheme.
db.createCollection("credentials", { validator: { $jsonSchema: { bsonType: "object", required: ["user_id", "credential_id", "attestation_type"], properties: { _id: { bsonType: "objectId" }, user_id: { bsonType: "objectId", description: "must be a valid ObjectId and is required" }, credential_id: { bsonType: "string", uniqueItems: true }, public_key: { bsonType: "string" }, attestation_type: { enum: ["direct", "indirect", "none"], description: "can only be one of the enum values and is required" }, aaguid: { bsonType: "string", default: "00000000-0000-0000-0000-000000000000" }, signature_count: { bsonType: "int" }, creation_date: { bsonType: "date", default: "$$NOW" }, last_used_date: { bsonType: "date" }, last_updated_date: { bsonType: "date", default: "$$NOW" }, type: { bsonType: "string" }, transports: { bsonType: "array", items: { bsonType: "string" } }, backup_eligible: { bsonType: "bool" }, backup_state: { bsonType: "bool" } } } } });
Well soon provide more details regarding the recommended users and credentials table for Cassandra. If you have urgent questions, feel free to reach out.
Well soon provide more details regarding the recommended users and credentials table for DynamoDB. If you have urgent questions, feel free to reach out.
Well soon provide more details regarding the recommended users and credentials table for Couchbase. If you have urgent questions, feel free to reach out.
This guide has explored recommendations for configuring databases for passkey authentication, addressing the complexities of database structures , and recommending optimal schemas for MySQL, PostgreSQL, SQLite and MongoDB. By embracing the guidelines and considerations presented, developers can save time by avoiding the need to devise their own database structures. While these are only recommendations and can be adjusted as needed, they serve as proven methods or a starting point to save time. As technology progresses, staying informed and adaptable is crucial for maintaining the integrity and security of our digital identities. We will continuously update this guide with new database technologies.
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.
Related Articles
9 WebAuthn Server Implementation Libraries Compared
Nicolai - December 15, 2023
The 34 Best Passkey SDKs and Libraries for Your Framework
Janina - September 19, 2023
Passkey Tutorial: How to Implement Passkeys in Web Apps
Vincent - December 7, 2023