# Welcome

Passport Protocol's documentation, SDKs, APIs, and infrastructure in general are currently in alpha state and are only meant to be used in production post our audit.&#x20;

With that in mind, please text us on Telegram **if you have any feedback, whatsoever.**  Our goal is to build **the best possible key management solution** you've ever come across - so please be ***brutally honest*** with your feedback!&#x20;

Thanks for joining us on this journey :)&#x20;

<figure><img src="/files/gIVi2M163NnZyoXmnNvo" alt=""><figcaption></figcaption></figure>


# Overview

[**Passport Protocol**](https://passport.0xpass.io) is a programmable and distributed, MPC-based, key management network.&#x20;

Using secure multi-party computation (MPC) algorithms Passport splits private keys into shares that are solely distributed among nodes in the network.&#x20;

## Benefits

### Non-Custodial and Secure&#x20;

Passport Protocol maintains a non-custodial system via network-custodial security. The network nodes operate under immutable rules using secure enclaves. Keys are encrypted and stored in a distributed database across nodes. Each node only ever contains a share of a user's private key.

The shares are protected by secure enclaves that isolate the keys from the node operators. Robust encryption ensures the database contents can only be accessed when enough nodes collaborate to reconstruct the key. This preserves user control without requiring self-hosted key management.

By blending distributed systems, cryptography, and programmability, Passport Protocol finally provides the flexible and easy-to-use key management that Web3 requires. This documentation will explore the protocol architecture, security guarantees, usage patterns, and ecosystem integration options that make Passport Protocol a game-changer for decentralized applications.

### Distributed Key Management

MPC algorithm and split private keys mean Passport can eliminate single points of failure and ensures no single entity ever has access to a user's full private key.&#x20;

### Truly Seedless

Unlike traditional MPC solutions that need the user to keep track of device or recovery shares, Passport can enable truly seedless onboarding where the user need not keep track of any shares - simplifying cross-device access while ensuring the most frictionless onboarding experience.&#x20;

### Programmability

Passport goes beyond traditional MPC by **making the the private keys fully programmable**.&#x20;

#### Programmable Authentication

Developers can define flexible authentication methods, including chaining together authentication methods, social logins, and customize key recovery options. Passport's unique "scopes" allow grouping keys and applying permissions and rules at the scope level.

#### Programmable Transactions

This programmability makes Passport extremely versatile. Developers can enable automated scheduled transactions, bot interactions, and novel user experiences.&#x20;

#### Programmable Portability

Passport also facilitates seamless wallet portability across apps through interoperable scopes.


# Background

Passport Protocol leverages advanced cryptographic and distributed systems innovations to ensure robust security and functionality. To understand the underlying principles of Passport, it's crucial to delve into the foundational concepts of modern cryptography and distributed systems.

Learn more here: \
[Threshold Cryptography](/how-passport-works/background/threshold-cryptography)\
[Secure Multi-Party Computation](/how-passport-works/background/secure-multi-party-computation)\
[Distributed Architecture](/how-passport-works/background/distributed-architecture)\
[Secure Enclaves](/how-passport-works/background/secure-enclaves)


# Threshold Cryptography

Threshold cryptography is a foundational concept in modern cryptographic systems, offering robust security by distributing the management of private keys across multiple entities. At its core, this technique involves dividing a private key into several shares or fragments, each entrusted to a different participant or node within a network. Unlike traditional cryptographic approaches where a single entity holds complete control over the private key, threshold cryptography distributes this responsibility among a group of designated parties.

The key feature of threshold cryptography lies in its threshold requirement, wherein a predefined number of shares must be combined to reconstruct the original private key. This threshold, often denoted as ( t ), determines the minimum number of shares needed for cryptographic operations. For instance, if ( t ) is set to a value less than or equal to the total number of shares ( n ), the private key can only be reconstructed when at least ( t ) shares are collected. This threshold mechanism adds an additional layer of security, as the compromise of individual shares alone is insufficient to compromise the entire key.

One of the primary advantages of threshold cryptography is its resilience to attacks and compromises. By distributing key management responsibilities across multiple entities, threshold cryptography eliminates single points of failure. Even if some shares are compromised, lost, or accessed by malicious parties, the integrity of the system remains intact as long as the threshold requirement is not breached. This resilience makes threshold cryptography particularly well-suited for environments where security and fault tolerance are paramount, such as distributed systems, blockchain networks, and multi-party protocols.

Furthermore, threshold cryptography facilitates secure cryptographic operations such as signing and decryption. Once the threshold of shares is collected, the original private key can be reconstructed, enabling authorized parties to perform cryptographic operations without exposing the complete key. This ensures that sensitive cryptographic functions can be executed securely, even in scenarios where trust among participants may be limited.

In Passport Protocol, threshold cryptography serves as a cornerstone of the system's security architecture. By leveraging threshold signatures, distributed key generation, and other threshold-based algorithms, Passport Protocol enhances the security and resilience of cryptographic operations, mitigating risks associated with single points of failure and unauthorized access. Through the decentralized distribution of key management responsibilities, Passport Protocol achieves a high level of security and trustworthiness, making it suitable for a wide range of applications where privacy, integrity, and resilience are paramount.


# Secure Multi-Party Computation

Secure Multi-Party Computation (MPC) is a sophisticated cryptographic technique that enables multiple parties to collaboratively compute a function over their private inputs while ensuring that no individual party learns anything beyond the result. It allows parties to jointly perform computations on their private data without revealing the data itself, thus preserving privacy and confidentiality.

In MPC, each party holds its own private input, which can be any form of sensitive data, such as personal information, financial records, or cryptographic keys. The goal is to compute a function over these inputs while preventing any party from learning more than what can be inferred from the function's output.

The fundamental principle underlying MPC is the concept of "secure function evaluation," where parties engage in a series of cryptographic protocols to compute the desired function securely. These protocols involve exchanging encrypted messages and performing operations on encrypted data in such a way that the final result is revealed without disclosing any party's private input.

For example, consider a scenario where two parties, Alice and Bob, wish to determine whether their salaries exceed a certain threshold without revealing their exact salaries to each other. Through MPC, Alice and Bob can jointly compute the function "salary > threshold" without disclosing their actual salary values. The result (true or false) is revealed to both parties without compromising their privacy.

Secure Multi-Party Computation (MPC) relies on the assumption that parties involved in the computation follow the prescribed protocol faithfully, known as being "honest." However, in real-world scenarios, parties may deviate from the protocol for various reasons, such as attempting to learn more about other parties' inputs or manipulating the computation's outcome.

There are two primary categories of party behavior in MPC: honest and malicious (or semi-honest).

1. Honest Behavior: where parties strictly adhere to the protocol and faithfully execute their assigned tasks without attempting to gain additional information about other parties' inputs or compromise the computation's integrity.
2. Semi-Honest or Malicious Behavior: where parties may deviate from the protocol in an attempt to gain unauthorized access to sensitive information or influence the computation's outcome in their favor.

In the context of MPC, security protocols are designed to mitigate the risks posed by semi-honest or malicious behavior. Techniques such as encryption, zero-knowledge proofs, commitment schemes, and cryptographic hashing are employed to ensure that parties cannot gain undue advantage or compromise the integrity of the computation.

By assuming the presence of semi-honest parties and designing protocols to withstand their attempts at manipulation, MPC achieves its goal of secure and privacy-preserving computation in adversarial environments. This resilience to potentially untrustworthy behavior is a cornerstone of MPC's effectiveness in real-world applications, including the Passport Protocol.

In the context of Passport Protocol, MPC is utilized in various critical operations, such as distributed key generation. When generating cryptographic keys, MPC ensures that no single entity possesses the complete key, thereby preventing unauthorized access or misuse. Instead, key shares are distributed among multiple parties, and computations are performed collaboratively to derive the final key without exposing any individual's share.

Specifically, Passport Protocol currently implements the following algorithms:

* [Threshold ECDSA in Three Rounds](https://eprint.iacr.org/2023/765.pdf)
* [Endemic Oblivious Transfer](https://eprint.iacr.org/2019/706)

Overall, MPC provides a powerful framework for enabling secure and privacy-preserving computation in decentralized and collaborative settings.


# Distributed Architecture

Distributed architecture represents a paradigm shift in system design, where computational tasks, data storage, and processing are distributed across multiple independent components or nodes. Unlike traditional centralized architectures, where a single entity controls all operations, distributed architectures distribute responsibilities across a network of nodes, offering scalability, fault tolerance, and resilience.

At the heart of distributed architecture lie several fundamental concepts. Decentralization is paramount, ensuring that decision-making authority and operational responsibilities are dispersed among nodes rather than concentrated in a central entity. Each node within the distributed system operates autonomously, performing specific tasks and communicating with other nodes via established protocols.

Communication protocols play a crucial role in enabling seamless interaction between nodes. These protocols define the rules and conventions for data exchange, synchronization, and message passing, facilitating coordination and collaboration among distributed components.

Consensus mechanisms are essential for achieving agreement among distributed nodes on the state of the system or the validity of transactions. Consensus ensures that all nodes reach a common understanding of the system's state, even in the presence of faulty or malicious nodes, thereby maintaining system integrity and consistency.

Replication strategies are employed to enhance fault tolerance and data availability by maintaining multiple copies of data across different nodes. By distributing and replicating data, distributed architectures ensure that information remains accessible even in the event of node failures or network partitions.

Scalability is another key aspect of distributed architectures, allowing systems to accommodate growing workloads and user demands by adding more nodes (horizontal scaling) or upgrading existing nodes (vertical scaling). Fault tolerance mechanisms further ensure system resilience by enabling continued operation in the face of failures or disruptions.

Security is paramount in distributed architectures, with cryptographic techniques such as encryption, digital signatures, and access control mechanisms employed to safeguard data confidentiality, integrity, and authenticity.

In the context of Passport Protocol, these core concepts are leveraged to create a network of distributed nodes owned by independent operators. By relying on distributed systems techniques such as consensus, replication, and fault tolerance, Passport ensures the integrity, security, and resilience of its decentralized architecture.


# Secure Enclaves

Secure enclaves, also known as trusted execution environments (TEEs), are hardware-based security features that provide a secure and isolated execution environment for sensitive computations and data. These enclaves are typically implemented as part of the CPU or as separate hardware components and offer protection against both physical and software-based attacks.

At the core of secure enclaves is the concept of isolation, which ensures that the code and data running inside the enclave are protected from unauthorized access or tampering, even by privileged system software or administrators. This isolation is achieved through hardware-enforced memory protection mechanisms that prevent external entities from accessing the enclave's memory space.

One of the primary use cases for secure enclaves is the protection of cryptographic keys and other sensitive data. In Passport Protocol, enclaves are utilized to safeguard key shares stored on individual nodes from potential compromise by node operators. By keeping the key shares encrypted and accessible only within the secure enclave, Passport ensures that even if a node is compromised, the keys remain protected from unauthorized access.

Secure enclaves also offer tamper-resistant features, making it extremely difficult for attackers to extract or manipulate the data and code running inside the enclave. These features include secure boot processes, memory encryption, and runtime integrity checks, which collectively enhance the overall security of the enclave and the data it processes.

By leveraging secure enclaves, Passport augments its distributed protections by adding an additional layer of security to its key management processes. Enclaves provide a trusted execution environment where sensitive operations can be performed with confidence, ensuring the confidentiality and integrity of cryptographic keys and other critical data.


# In Depth

Learn more about how Passport Protocol works, in depth.

This section explores the underlying components that make up Passport Protocol in depth exploring all the interactions under the hood, our approach to security, and our long term roadmap on Node operation.

[User Flows and Account Controls](/how-passport-works/in-depth/user-flows-and-account-controls)

[Under the Hood](/how-passport-works/in-depth/under-the-hood)

[The Halides Model](/how-passport-works/in-depth/the-halides-model)

[End-to-End Encryption](/how-passport-works/in-depth/end-to-end-encryption)

[Security](/how-passport-works/in-depth/security)

[Node Operation](/how-passport-works/in-depth/node-operation)


# Under the Hood

Passport Protocol operates through a meticulously designed process that ensures the security and integrity of cryptographic key management. Here's a detailed overview of the internals:

{% hint style="info" %}
For the full version of this chapter, check out our blog post on Passport's technical architecture [*here*](https://blog.0xpass.io/p/introducing-passport-protocol-programmable)
{% endhint %}

<figure><img src="/files/Cteb8XQrGADZwOVot2GV" alt=""><figcaption><p>Passport Nodes</p></figcaption></figure>

### Distributed Key Generation

Passport Networks divide the creation and storage of private keys across multiple nodes. Each node in the network  jointly executes a multi-party computation (MPC) protocol to a "share" of the private key, which is then stored in an encrypted database through secure enclaves. This distributed approach ensures that:

* Keys are never stored in one location, reducing single points of failure.
* No one, not even the node operator has the access to the key share in any process.
* The network offers strong fault tolerance and resilience.

By distributing key generation in this manner, Passport eliminates single points of failure and enhances privacy, as no single entity has access to the complete private key.

### Secure Key Storage

The shares of the private key are encrypted and stored across various nodes. Thanks to secure enclaves' hardware-based security, node operators can't see the key segments. Strong encryption allows only authorized reconstruction of key segments for signing, protecting them against unauthorized access.

### Programmability Through Scopes

Passport uses "scopes" to define authentication and permission levels for keys, giving developers the ability to customize these according to their needs. This flexibility empowers developers to:

* Customize with different account controls and authentication rules:
  * user-controlled - require only user signature
  * developer-controlled - require only developer signature
  * hybrid account (multi-sig) - require both user and developer signature&#x20;
* Offer custom recovery options.

### Performance and Scalability

Passport Network targets sub-second performance for processing any user actions. It employs peer-reviewed algorithms and audited implementations. Specifically, it uses [DKLS23](https://eprint.iacr.org/2023/765) for threshold signatures. This algorithm offers:

* High performance with the lowest latency possible in Multi-Party Computation Threshold Signature Schemes (MPC-TSS).
* Robustness by avoiding the computationally-intensive Paillier operations commonly found in traditional MPC solutions.

### Transaction Signing

Upon successful authentication, clients can request transaction signatures from Passport. The appropriate private key share is temporarily reconstructed from encrypted shares to generate signature shares for the requested transaction. Signing permissions are configured on a per-scope basis, allowing for granular control over signing capabilities. Certain scopes may permit scheduled, automated signing processes, while others require explicit user approval, depending on the application's security requirements and user preferences.

### Programmatic Signing

<figure><img src="/files/Dcq6HBdAptmchvRYTgzU" alt=""><figcaption><p>Programmatic Signing</p></figcaption></figure>

With the entire key managed by the network, transactions can be executed programmatically based on set conditions, like performing an auto-swap when ETH hits a certain price.

### Recovery and Revocation

Passport offers flexible recovery mechanisms, including backup codes for self-serve account recovery, social login options for passwordless recovery, and revocation procedures in the event of key compromise. Automated key rotation processes further enhance security by periodically refreshing cryptographic keys to mitigate the risk of prolonged exposure. These recovery and revocation flows are designed to uphold strong security guarantees through the use of MPC and threshold cryptography, ensuring the integrity and confidentiality of cryptographic operations in Passport Protocol.

<br>


# User Flows and Account Controls

Passport Protocol operates through a meticulously designed process that ensures the security and integrity of cryptographic key management. Here's a detailed overview of how it works:

### Typical User Flows

*This is a diagram showcasing how our Passkeys auth flow works*

<figure><img src="/files/msFrJnfYqtYIpDUGTFcF" alt=""><figcaption><p>High Level Sequence Diagram of App &#x3C;> Passport &#x3C;> User Interaction</p></figcaption></figure>

### Account Controls

<figure><img src="/files/sN2oUn44CIPh8SH6pvez" alt=""><figcaption><p>Types of Components used for Passport Protocol</p></figcaption></figure>

Here are the core components of Passport Protocol:

* **Scope**: Application level configuration
* **User Action**: Any use of an account (ex, signing)
* **Policy**: Set of rules that govern the use and access of an account
* **Credentials**: verifies access to an account.
* **Account**: contains information about credentials and the MPC generated keys


# The Halides Model

Passport’s goal is to be the ***most performant distributed network***. As a result, we lean towards pragmatism which in turn means that while our network is distributed, it is closed and permissioned.

This way we control the quality and the size of the network, allowing us to optimize for performance and cost. As a result of our goal, our network’s design and our plan to scale it are also vastly different from traditional approaches.

### Traditional

<figure><img src="/files/jycW7s5FMlD2dbotdsap" alt=""><figcaption></figcaption></figure>

Traditional approaches to distributed key management rely on

* Increasing the volume of nodes to be more open
* Offloading most key network tasks such as authentication, communication, etc to the nodes themselves. This is in addition to the nodes storing the key shares themselves.

While this does make the network more open, it poses a couple of issues -

* For any key related operations, the client has to communicate with all of the nodes in addition to the nodes communicating with each other. This slows down the performance as the size of the network grows

<figure><img src="/files/cWNPJKCDumFD2PERLDy9" alt=""><figcaption></figcaption></figure>

### Passport’s Approach - The Halides Framework

Our team came up with a new approach to scaling our network, called “Halides” that optimizes for performance.

* Unlike the traditional model, we introduce a new component called the orchestrator and reduce the nodes’ job to managing key shares and nothing else. The orchestrator handles everything else such as authentication (via enclaves), communication and more.

<figure><img src="/files/zVcqvFv5Py75cnuYup9d" alt=""><figcaption></figcaption></figure>

* Secondly the key shares in the nodes are further broken down into chunks and these chunks are clustered into what we call “halides”.

<figure><img src="/files/aaSIYoJtthk1rqU98GUZ" alt=""><figcaption></figcaption></figure>

This way, the client only talks to the orchestrator which in turn is optimized to handle all other sorts of communication. And our key chunk distribution ensures that at the macro level, the volume or the size of the network is minimized while still being able to distribute smaller key chunks of the share.

<figure><img src="/files/CTU0WkOYgH8Nz5xDrbRq" alt=""><figcaption></figcaption></figure>

While this introduces a “trust-minimized” layer called the orchestrator, it allows us to boost the overall performance of the network. It also opens up the possibility for there to be multiple orchestrator vendors in the future.

## Deepdive

If you'd like to deepdive into the Halides model, take a look at our whitepaper (in draft) [here](https://docs.google.com/document/d/17tl8VHcxVffpLi3AJB9aOYfaKXwF7dJ0iq-nk27fsE0/edit?usp=sharing).&#x20;


# End-to-End Encryption

<figure><img src="/files/WvZRZDIJG0x9rDeUSjTO" alt=""><figcaption><p>End to end encryption flow</p></figcaption></figure>

End-to-end encryption prevents third-parties from accessing data while it's transferred from one end system to another. In this scenario, even the operators of the network nodes that facilitate the communication cannot see the payload in plain text.

Here's how it works, enhanced by the use of secure enclaves and the AES key encryption scheme:

**Encryption:**

* Your device generates a temporary AES key for symmetric encryption, ensuring that the message can be encrypted and decrypted quickly and securely.
* The message is encrypted using this AES key, turning the plaintext into ciphertext.
* The AES key is encrypted using a public RSA key that originates from a secure enclave. Consequently, only within the secure enclave, which possesses the matching private RSA key, can the AES key be decrypted.

**Transmission:**

* The encrypted message (ciphertext) and the encrypted AES key are sent across the internet.
* encrypted AES key is also sent through the `x-encrypted-key` header
* Anyone who might intercept the message during transmission, including node operators, cannot decipher it because they don't have the necessary private RSA key to decrypt the AES key, and thus cannot decrypt the message itself.

**Decryption:**

* Upon arrival, the receiver's device uses a secure enclave, a highly protected area in the processor, to safely use their private RSA key to decrypt the encrypted AES key.
* The secure enclave then uses the decrypted AES key to decrypt the message, restoring it to its original, readable form.

The secure enclave ensures that the decryption process is isolated from the rest of the system, adding an extra layer of security. Even if the network is compromised, or the node operators are malicious, they cannot access the private RSA key or the unencrypted data. Only the intended recipient, with the private RSA key securely stored in their enclave, can decrypt and read the message.


# Security

Ensuring the highest level of security remains paramount in the Passport Protocol's design. This chapter delves into Passport's refined threat model, emerging attack vectors, and cutting-edge mitigation strategies.

### Threat Model

The threat model encompasses a comprehensive spectrum of potential risks, including compromised nodes, malicious actors, and sophisticated network attacks. The evolving threat landscape also necessitates a nuanced understanding of potential risks. Key threats include:

* **Unauthorized Access Attempts**: Node operators may attempt to gain unauthorized access to sensitive data or cryptographic secrets.
* **External Intrusions**: Sophisticated external attackers could compromise network nodes to manipulate data or extract valuable information.
* **Identity Spoofing**: Malicious users might attempt to impersonate legitimate users to gain unauthorized access to resources or disrupt operations.
* **Message Manipulation**: Adversaries may try to manipulate or intercept messages within the network to disrupt operations or compromise data integrity.
* **Supply Chain Compromises**: Heightened awareness of supply chain vulnerabilities, including compromised dependencies and malicious software updates.
* **Zero-Day Exploits**: Rapid detection and mitigation of zero-day vulnerabilities to prevent exploitation by adversaries.
* **Insider Threats**: Mitigating risks posed by insider threats, including compromised node operators or malicious insiders with access to sensitive systems.
* **Quantum Computing Risks**: Anticipating the potential impact of quantum computing on traditional cryptographic algorithms and proactively preparing for post-quantum cryptography adoption.

### Attack Vectors

Identifying and understanding potential attack vectors is crucial for preemptive defense. Some notable attack vectors include:

* **Node Exploitation**: Exploiting vulnerabilities in node software or underlying infrastructure to gain unauthorized access or compromise security.
* **Collusion Attacks**: Coordinated efforts among a majority of nodes to undermine security mechanisms or reconstruct cryptographic secrets.
* **Network partitioning** - Splitting the network could disable services. Mitigated through redundancy across regions, providers, and protocols.
* **Software distribution pipelines** - Compromised updates could insert vulnerabilities. Mitigated through signed updates, staged rollouts, and monitoring.
* **Quantum computing attacks** - QC could break underlying crypto assumptions. Mitigated by upgradability to post-quantum schemes.

### Mitigation Strategies

Passport Protocol implements a robust suite of mitigation strategies to address identified risks and bolster overall security posture:

* **Dynamic Secret Managemen**t: Proactive secret rotation and dynamic key management practices to minimize exposure and mitigate the impact of compromised secrets.
* **Secure Communication Protocols:** Utilization of state-of-the-art encryption and secure communication channels to safeguard data in transit and prevent man-in-the-middle attacks.
* **Hardware-backed Security**: Leveraging hardware-based security mechanisms, such as secure enclaves, to protect cryptographic keys and sensitive operations from unauthorized access or tampering.
* **Fine-Grained Access Controls**: Implement granular access controls at the hardware level, allowing each Passport component to access only the resources it requires to function, thereby minimizing the attack surface and potential impact of a breach.
* **Immutable Infrastructure**: Immutable configurations and deployment practices to prevent unauthorized modifications or tampering with critical system components.
* **Threshold Cryptography**: Implementation of threshold cryptography techniques to distribute trust and prevent single points of compromise, enhancing resilience against node-level attacks.
* **Continuous Monitoring and Auditing**: Robust monitoring, logging, and auditing mechanisms to detect anomalies, unauthorized access attempts, or suspicious activities in real-time.
* **Community Engagement**: Engagement with external security researchers, bug bounty programs, and regular security audits to identify and address vulnerabilities proactively.
* **Immutable Configurations for Deployment Pipeline:** Maintain immutable configurations for Passport deployment pipeline, preventing unauthorized modifications that could compromise the integrity of the system. Any changes to configurations should undergo thorough validation and approval processes.
* **Zero Trust Architecture**: Adoption of a zero-trust security model, emphasizing strict access controls, micro-segmentation, and continuous authentication.
* **Behavioral Analytics**: Implementation of behavioral analytics and anomaly detection techniques to identify suspicious activities and potential security breaches.

Evolution of Security As the Passport Protocol continues to evolve, security remains a central focus area. Continuous refinement of threat models, proactive risk assessments, and adoption of emerging security best practices ensure that Passport maintains its resilience against evolving threats and vulnerabilities. The collaborative effort of the Passport community, combined with ongoing research and innovation, reinforces the protocol's security posture and resilience in the face of emerging challenges.

The system grows stronger as the network expands and diversifies, which we discuss in [Node Operation](/how-passport-works/in-depth/node-operation).


# Node Operation

Passport Protocol will operate as a distributed and permissioned network of vetted node operators to ensure performance and reliability.&#x20;

The decentralization roadmap focuses on:

* **Node operator decentralization** - Diversifying node operators to ensure integrity
* **Incentive decentralization** - Distributing economic rewards algorithmically based on contributions

### Transparency

Throughout the whole process, 0xPass will maintain transparency by:

* Sharing the roadmap and criteria for node participation
* Disclosing the identities of initial node operators
* Releasing open source code for community review
* Providing public channels for feedback and questions

The community will have insight into Passport's evolution towards decentralization.

### Phases

Decentralization will be phased across 4 stages:

#### Phase 1: Distributed Nodes

This initial phase implements distribution for security:

* **Proactive secret sharing** - Periodic share rotation
* **MPC** - Prevents single node key compromise
* **Secure enclaves** - Hardware-isolated computation

#### Phase 2: Third-Party Node Operators

Onboarding third-party operators with mechanisms like:

* **Reputation systems** - Track node reliability
* **Random sampling** - Prevent collusion
* **Governance** - Community-driven decisions
* **Opensource**

#### Phase 3: Scalability

Scaling the network through optimizations like **Sharding.** The focus of this phase is to allow the network to have more node operators.

#### Phase 4: Incentives

Introducing decentralized incentives:

* **Tokenomics** - Network tokens for compensation
* **Fee mechanisms** - Usage-based distribution

### Onboarding Node Operators

Upon reaching Phase 2, operators can run nodes by installing the software. Incentives will encourage diverse participation.


# Getting Started

Getting started with Passport requires the following steps&#x20;

## Step 1 - Configure Authentication Rules

Every account created on Passport has an authentication "scope" associated with it.&#x20;

Scopes are objects that allow you to configure and program the authentication, recovery rules that govern how your users can interact with the Passport network and their keys.&#x20;

**Note: Scopes DO NOT give you control over any keys.** They are simply just the configuration rules around what authentication methods you'd like to support.

To configure your scope, check out this chapter -

&#x20;[Configuring your scope](/authentication/configuring-your-scope)

{% hint style="success" %}
Want to jump right into the code? Check out the [Quickstarts and Examples](/guides-and-examples/quickstarts-and-examples) section after Step 1
{% endhint %}

## Step 2 - Interact With Passport

Once you're done setting up your account and configuring scopes, you are now all set!&#x20;

You can interact with the network to&#x20;

* [Register and Authenticate users](/authentication/overview)
* [Sign Messages and Transactions](/wallet-operations/overview)
* [Create and Execute Programmable Transactions](/programmability/overview)


# Quickstarts and Examples

Getting started with interacting with Passport Protocol

{% content-ref url="/pages/6vtP61IFwDBbZ8FYyLhs" %}
[Passkey Account](/guides-and-examples/quickstarts-and-examples/passkey-account)
{% endcontent-ref %}

{% content-ref url="/pages/2s6k2WvWJ8NH2mQNTIN9" %}
[Lambda Quickstart](/guides-and-examples/quickstarts-and-examples/lambda-quickstart)
{% endcontent-ref %}


# Passkey Account

This quick start guide will walk you through how to quickly get setup with the Passport SDK, register and authenticate users, and start signing messages and transactions. You can skip to the [#complete-setup](#complete-setup "mention"), and then follow the section step-by-step where each code snippet will be explained. You can also quickly pull the completed repository here <https://github.com/0xpass/passport-quickstart> and follow along.

### Project setup

First we'll setup a Next.js project, with tailwind, we can do this with the following command, and walk through the configuration wizard, making sure to chose the app-router, and tailwind.

```bash
npx create-next-app@latest
```

### Setup and Dependencies

Firstly, we'll ensure we have all the requires dependencies. So we're going to install the Passport SDK **`@0xpass/passport`** to interact with Passport protocol, and `viem` for blockchain interactions. We'll also install some helper packages **`@0xpass/passport-viem`** to seamlessly use **`Passport`** with **`viem`**, and finally **`@0xpass/webauthn-signer`** to handle our passkey registration and authentication.

{% tabs %}
{% tab title="npm" %}

```bash
npm install @0xpass/passport @0xpass/passport-viem @0xpass/webauthn-signer viem@1.16.6 
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm install @0xpass/passport @0xpass/passport-viem @0xpass/webauthn-signer viem@1.16.6 
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add @0xpass/passport @0xpass/passport-viem @0xpass/webauthn-signer viem@1.16.6 
```

{% endtab %}
{% endtabs %}

Firstly let's setup a **`usePassport`** hook, which gives us an easy way to access our **`Passport`** instance.&#x20;

```typescript
import { useRef } from "react";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { Network, Passport } from "@0xpass/passport";

export function usePassport(scopeId: string) {
  const signerRef = useRef<WebauthnSigner | null>(null);
  const passportRef = useRef<Passport | null>(null);

  if (!signerRef.current) {
    signerRef.current = new WebauthnSigner({
      rpId: process.env.NEXT_PUBLIC_RP_ID!,
      rpName: "0xPass",
    });
  }

  if (!passportRef.current) {
    passportRef.current = new Passport({
      scopeId: scopeId,
      signer: signerRef.current,
      network: Network.TESTNET,
    });
  }

  return {
    passport: passportRef.current,
    signer: signerRef.current,
  };
}
```

Now in our **`page.tsx`** we can setup our state variables for, tracking registering, and authenticating users. We'll also use our **`Passport`** and **`WebauthnSigner`** instances, from the hook we just created. as well as our Alchemy url and a fallback provider, which we'll make use of when we want to signMessages with our **`WalletClient`**.

```typescript
"use client";
import { useState } from "react";
import { createPassportClient } from "@0xpass/passport-viem";
import { http } from "viem";
import { mainnet } from "viem/chains";
import { usePassport } from "./hooks/usePassport";

export default function Page() {
  const [username, setUsername] = useState("");
  const [authenticated, setAuthenticated] = useState(false);
  const [authenticating, setAuthenticating] = useState(false);
  const [registering, setRegistering] = useState(false);
  const [authenticateSetup, setAuthenticateSetup] = useState(false);
  const [signMessageLoading, setSignMessageLoading] = useState(false);
  const [message, setMessage] = useState("");
  const [messageSignature, setMessageSignature] = useState("");
  const [authenticatedHeader, setAuthenticatedHeader] = useState({});
  const [address, setAddress] = useState<string>();

  const alchemyUrl = process.env.NEXT_PUBLIC_ALCHEMY_URL!;
  const fallbackProvider = http(alchemyUrl);

  const userInput = {
    username: username,
    userDisplayName: username,
  };

  const { passport } = usePassport("07907e39-63c6-4b0b-bca8-377d26445172");
```

We use a **`useRef`** so that a new instance of **`WebauthnSigner`** and **`Passport`** aren't re-created during re-renders.

Next up we're going to setup our **`WalletClient`** with viem,  our functions to register and authenticate users, as well as sign messages.

So we set up the functions for these as follows, we setup the **`register` , `authenticate`** and **`signMessage`** functions, as well as our **`createWalletClient`** function which allows us to set up client to use any **`viem`** functionality.&#x20;

```typescript
  async function register() {
    setRegistering(true);
    try {
      await passport.setupEncryption();
      const res = await passport.register(userInput);
      console.log(res);

      if (res.result.account_id) {
        setRegistering(false);
        setAuthenticating(true);
        await authenticate();
        setAuthenticating(false);
      }
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setRegistering(false);
      setAuthenticating(false);
    }
  }

  async function authenticate() {
    setAuthenticating(true);
    try {
      await passport.setupEncryption();
      const [authenticatedHeader, address] = await passport.authenticate(
        userInput
      )!;
      setAuthenticatedHeader(authenticatedHeader);
      console.log(address);
      setAddress(address);
      setAuthenticated(true);
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setAuthenticating(false);
    }
  }

  async function createWalletClient() {
    return await createPassportClient(
      authenticatedHeader,
      fallbackProvider,
      mainnet
    );
  }

  async function signMessage(message: string) {
    try {
      setSignMessageLoading(true);
      const client = await createWalletClient();
      const [address] = await client.getAddresses();
      const response = await client.signMessage({
        account: address,
        message,
      });

      setMessageSignature(response);
      setSignMessageLoading(false);
    } catch (error) {
      console.error(error);
    }
  }
```

### Complete Setup

Now with all of this setup we can setup our UI too, so the overall setup looks as below. In the final part of our setup, we've created the UI layer to interact with the above functions. We have buttons to register and authenticate, which dynamically interact with the state, to show loading states, as well as authenticated states, and finally when a message is signed, the user is also able to see the signed message signature.

```typescript
"use client";
import { useState } from "react";
import { createPassportClient } from "@0xpass/passport-viem";
import { http } from "viem";
import { mainnet } from "viem/chains";
import { usePassport } from "./hooks/usePassport";

export default function Page() {
  const [username, setUsername] = useState("");
  const [authenticated, setAuthenticated] = useState(false);
  const [authenticating, setAuthenticating] = useState(false);
  const [registering, setRegistering] = useState(false);
  const [authenticateSetup, setAuthenticateSetup] = useState(false);
  const [signMessageLoading, setSignMessageLoading] = useState(false);
  const [message, setMessage] = useState("");
  const [messageSignature, setMessageSignature] = useState("");
  const [authenticatedHeader, setAuthenticatedHeader] = useState({});
  const [address, setAddress] = useState<string>();

  const alchemyUrl = process.env.NEXT_PUBLIC_ALCHEMY_URL!;
  const fallbackProvider = http(alchemyUrl);

  const userInput = {
    username: username,
    userDisplayName: username,
  };

  const { passport } = usePassport("07907e39-63c6-4b0b-bca8-377d26445172");

  async function register() {
    setRegistering(true);
    try {
      await passport.setupEncryption();
      const res = await passport.register(userInput);
      console.log(res);

      if (res.result.account_id) {
        setRegistering(false);
        setAuthenticating(true);
        await authenticate();
        setAuthenticating(false);
      }
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setRegistering(false);
      setAuthenticating(false);
    }
  }

  async function authenticate() {
    setAuthenticating(true);
    try {
      await passport.setupEncryption();
      const [authenticatedHeader, address] = await passport.authenticate(
        userInput
      )!;
      setAuthenticatedHeader(authenticatedHeader);
      console.log(address);
      setAddress(address);
      setAuthenticated(true);
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setAuthenticating(false);
    }
  }

  async function createWalletClient() {
    return await createPassportClient(
      authenticatedHeader,
      fallbackProvider,
      mainnet
    );
  }

  async function signMessage(message: string) {
    try {
      setSignMessageLoading(true);
      const client = await createWalletClient();
      const [address] = await client.getAddresses();
      const response = await client.signMessage({
        account: address,
        message,
      });

      setMessageSignature(response);
      setSignMessageLoading(false);
    } catch (error) {
      console.error(error);
    }
  }

  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2 bg-white text-black">
      <div
        className={`text-2xl font-bold mb-8 ${
          authenticated ? "text-green-500" : "text-red-500"
        }`}
      >
        {authenticated ? "Authenticated" : "Not authenticated"}
      </div>
      <div className="text-center">
        <h1 className="text-3xl font-bold underline">
          Passport Protocol Quickstart
        </h1>
        <p className="mt-2 text-lg">
          This is a quickstart guide for the Passport Protocol SDK.
        </p>

        <div className="flex flex-col mt-4 space-y-4">
          {authenticated ? (
            <>
              <div className="flex flex-col space-y-4">
                <div className="flex items-center justify-between">
                  <div className="font-bold">Address</div>
                  <div>{address}</div>
                </div>
              </div>

              {messageSignature && (
                <div className="flex flex-col space-y-4 max-w-[60ch] break-words">
                  <div className="font-bold">Message Signature</div>
                  <div>{messageSignature}</div>
                </div>
              )}

              <input
                value={message}
                onChange={(e) => setMessage(e.target.value)}
                className="border border-1 rounded p-2 border-black mb-4 ml-2 text-center"
                placeholder="Message to sign"
              />
              <button
                onClick={async () => await signMessage(message)}
                disabled={signMessageLoading}
                className="border border-1 rounded p-2 border-black mb-4 ml-2"
              >
                {signMessageLoading ? "Signing..." : "Sign Message"}
              </button>
            </>
          ) : (
            <div className="mb-12 flex flex-col space-y-2 mt-8">
              <input
                value={username}
                onChange={(e) => setUsername(e.target.value)}
                className="border border-1 rounded p-2 border-black mb-4 ml-2 text-center"
                placeholder="Enter unique username"
              />
              <button
                className="border border-1 rounded p-2 border-black mb-4 ml-2"
                onClick={async () => {
                  if (authenticateSetup) {
                    await authenticate();
                  } else {
                    await register();
                  }
                }}
                disabled={registering || authenticating}
              >
                {authenticateSetup
                  ? authenticating
                    ? "Authenticating..."
                    : "Authenticate"
                  : registering
                  ? "Registering..."
                  : authenticating
                  ? "Authenticating..."
                  : "Register"}
              </button>

              <span
                onClick={() => setAuthenticateSetup(!authenticateSetup)}
                className="cursor-pointer"
              >
                {authenticateSetup
                  ? "Register a Passkey?"
                  : "Already have a passkey?"}
              </span>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
```


# Clerk Auth

This quick start guide will walk you through how to quickly get setup with the Passport SDK with Clerky account, register and authenticate users, and start signing messages and transactions. You can skip to the [#complete-setup](#complete-setup "mention"), and then follow the section step-by-step where each code snippet will be explained. You can also quickly pull the completed repository here  <https://github.com/0xpass/passport-clerk-quickstart> and follow along.

### Project setup

First we'll setup a Next.js project, with tailwind, we can do this with the following command, and walk through the configuration wizard, making sure to chose the app-router, and tailwind.

```bash
npx create-next-app@latest
```

### Setup and Dependencies

Firstly, we'll ensure we have all the requires dependencies. So we're going to install the Passport SDK **`@0xpass/passport`** to interact with Passport protocol, and `@clerk/nextjs` for third party authentication. We'll also install some helper packages **`@0xpass/key-signer`** to handle our signature management for delegated registration and authentication.

{% tabs %}
{% tab title="npm" %}

```bash
npm install @0xpass/passport @0xpass/key-signer @clerk/nextjs@4.2.9 viem@2.9.4
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm install @0xpass/passport @0xpass/key-signer @clerk/nextjs@4.2.9 viem@2.9.4
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add @0xpass/passport @0xpass/key-signer @clerk/nextjs@4.2.9 viem@2.9.4
```

{% endtab %}
{% endtabs %}

### Environment Variables and Generating Developer Keys

In your project root, copy and paste the environment variables below.

```shellscript
NEXT_PUBLIC_SCOPE_ID=""
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=""
CLERK_SECRET_KEY=""
PRIVATE_KEY=""
```

Going one by one,

NEXT\_PUBLIC\_SCOPE\_ID can get obtained from [Configuring your scope](/authentication/configuring-your-scope)

You should grab your own NEXT\_PUBLIC\_CLERK\_PUBLISHABLE\_KEY, and CLERK\_SECRET\_KEY from your Clerk account.&#x20;

For Developer Key (PRIVATE\_KEY), follow [Generating DOA Keys](/appendix/generating-doa-keys) for generating your own keys. We'll refer to the private key generated in this step as `PRIVATE_KEY` environment variable in the example below.&#x20;

### Backend APIs

Firstly let's setup backend API for creating an account in passport protocol upon successful authentication via Clerk.&#x20;

Authentication Flow:

<figure><img src="/files/TXi7HPx2Em4wj0tfbLLC" alt=""><figcaption></figcaption></figure>

Signing Flow:

<figure><img src="/files/gEkTlSBjb5lsX0Zs5bKG" alt=""><figcaption></figcaption></figure>

This is not a part of backend, but you need a page that takes the callback from clerk, and redirects to /api/user-callback. In `app/auth/callback` we'll have the following snippet so that frontend calls the backend endpoint with user id and email address upon successful sign-in.

```typescript
"use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { useUser } from "@clerk/nextjs";

export default function CallbackPage() {
  const router = useRouter();
  const { isLoaded, isSignedIn, user } = useUser();

  useEffect(() => {
    if (isLoaded && isSignedIn) {
      fetch("/api/user-callback", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          userId: user.id,
          emailAddress: user.emailAddresses[0].emailAddress,
        }),
      })
        .then((response) => response.json())
        .then(() => {
          router.push("/");
        })
        .catch((error) => {
          console.error("Error:", error);
        });
    }
  }, [isLoaded, isSignedIn, user, router]);

  return <div>Processing...</div>;
}

```

We'll create a file at:`app/api/user-callback/route.ts`  Which will create a Passport instance with KeySigner with your private key. PRIVATE\_KEY environment variable can point to a file path or the actual private key. Note that the private key should only be handled in your backend, and can't be exposed publicly.

```typescript
import { NextResponse } from "next/server";
import { KeySigner } from "@0xpass/key-signer";
import { Passport } from "@0xpass/passport";

export async function POST(req: Request) {
  const payload = await req.json();
  const keySigner = new KeySigner(process.env.PRIVATE_KEY!, true);

  const passport = new Passport({
    scope_id: process.env.NEXT_PUBLIC_SCOPE_ID!,
    signer: keySigner,
  });

  await passport.setupEncryption();
  const data = await passport.delegatedRegisterAccount({
    username: payload.emailAddress,
  });

  return NextResponse.json(data);
}
```

After authenticating with Clerk, you can directly interact with Passport with the username (email from Clerk) and your developer keys.

Now we'll implement `get-account`endpioint at `app/api/get-account/route.ts`.  For retrieving your user's email address you can use `currentUser()` function which will grab user information from the session established with Clerk.&#x20;

```typescript
import { currentUser } from "@clerk/nextjs/server";
import { KeySigner } from "@0xpass/key-signer";
import { Passport } from "@0xpass/passport";

export async function GET() {
  try {
    const user = await currentUser();
    if (!user) {
      return new Response("Unauthorized", { status: 401 });
    }

    const keySigner = new KeySigner(process.env.PRIVATE_KEY!, true);
    const passport = new Passport({
      scope_id: process.env.NEXT_PUBLIC_SCOPE_ID!,
      signer: keySigner,
    });

    passport.setUserData({ username: user.emailAddresses[0].emailAddress });
    await passport.setupEncryption();
    const addresses = await passport.getAddresses();
    return new Response(JSON.stringify(addresses), { status: 200 });
  } catch (error) {
    console.log(error);
    return new Response("Something went wrong", { status: 500 });
  }
}

```

Lastly, we're using `signing message` as an example of user action. In `app/api/sign/route.ts`, implement the following function.&#x20;

```typescript
import { NextResponse } from "next/server";
import { currentUser } from "@clerk/nextjs/server";
import { KeySigner } from "@0xpass/key-signer";
import { Passport } from "@0xpass/passport";
import { stringToHex } from "viem";

export async function POST(req: Request) {
  const payload = await req.json();
  const { type, data } = payload;

  const user = await currentUser();

  if (!user) {
    return new Response("Unauthorized", { status: 401 });
  }

  const keySigner = new KeySigner(process.env.PRIVATE_KEY!, true);
  const passport = new Passport({
    scope_id: process.env.NEXT_PUBLIC_SCOPE_ID!,
    signer: keySigner,
  });

  passport.setUserData({ username: user.emailAddresses[0].emailAddress });
  await passport.setupEncryption();
  const signature = await passport.signMessage(stringToHex(data));
  return NextResponse.json({ signature });
}
```

### Middleware

Under  app directory, we need a middleware to keep the authenticated user context across the backend apis and the frontend.

```typescript
import { authMiddleware } from "@clerk/nextjs/server";

export default authMiddleware({
  publicRoutes: ["/", "/auth/callback", "/lambda"],
});

export const config = {
  matcher: ["/((?!.+\\.[\\w]+$|_next).*)", "/", "/(api|trpc)(.*)"],
};

```

### Frontend

### Clerk Providers

First we'll need to make sure we wrap our application inside the `ClerkProvider` . We can do this by creating a new file `providers.tsx` inside the `src` directory, and populating it as below.

```typescript
"use client";
import { ClerkProvider } from "@clerk/nextjs";

export function Providers({ children }: { children: JSX.Element }) {
  return <ClerkProvider>{children}</ClerkProvider>;
}
```

Then we can now wrap our app with our Provider by going to `src/layout.tsx` and adjusting it so it looks like this&#x20;

```typescript
import { Inter } from "next/font/google";
import { Providers } from "./providers";
import localFont from "next/font/local";
import "./globals.css";

const myFont = localFont({ src: "../../public/fonts/PPNeueMontreal-Book.otf" });

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <Providers>
        <body className={`${myFont.className} bg-black text-white`}>
          {children}
        </body>
      </Providers>
    </html>
  );
}
```

Now in our **`page.tsx`** we can setup our state variables for, tracking registering, and authenticating users.&#x20;

```typescript
"use client";
import { useState } from "react";
import { SignUpButton, useUser, SignOutButton } from "@clerk/nextjs";
import { useEffect } from "react";

export default function Page() {
  const { isSignedIn, isLoaded } = useUser();
  const [authenticated, setAuthenticated] = useState(false);
  const [signMessageLoading, setSignMessageLoading] = useState(false);
  const [message, setMessage] = useState("");
  const [messageSignature, setMessageSignature] = useState({
    signature: "",
    timeTaken: 0,
  });
  const [address, setAddress] = useState<string>();
  const [addressLoading, setAddressLoading] = useState(false);
```

For fetching the address of the current user, we'll use the function below

```typescript
  const fetchDelegatedAddress = async () => {
    setAddressLoading(true);
    try {
      if (!addressLoading) {
        const response = await fetch("/api/get-account", {
          method: "GET",
        });

        if (response.ok) {
          const addresses = await response.json();
          setAddress(addresses.result[0]);
        }
      }
    } catch (error) {
      console.log(error);
    } finally {
      setAddressLoading(false);
    }
  };
```

and we'll trigger this function once when the page loads:

```typescript
  useEffect(() => {
    if (isSignedIn) {
      fetchDelegatedAddress();
    }
  }, [isSignedIn]);
```

We also need a handler for when user click on sign button:

```typescript
  async function delegatedSignMessage(message: string) {
    setSignMessageLoading(true);
    try {
      const startTime = performance.now();
      let response = await fetch("/api/sign", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          type: "message",
          data: message,
        }),
      });

      if (response.ok) {
        const { signature } = await response.json();
        const timeTaken = performance.now() - startTime;
        setMessageSignature({
          signature: signature.result,
          timeTaken: timeTaken,
        });
      } else {
        throw Error(`HTTP error: ${response}`);
      }
    } catch (e) {
      console.error(e);
    } finally {
      setSignMessageLoading(false);
    }
  }
```

Lastly, we'll work on the presentation of this page.&#x20;

Before we get to the main part, we'll display a spinner to wait for Clerk to determine whether this person is authenticated or not.

```typescript
  if (!isLoaded) {
    return (
      <div className="h-screen w-full flex items-center justify-center">
        <svg
          className="animate-spin h-12 w-12 text-white"
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
        >
          <circle
            className="opacity-25"
            cx="12"
            cy="12"
            r="10"
            stroke="currentColor"
            strokeWidth="4"
          ></circle>
          <path
            className="opacity-75"
            fill="currentColor"
            d="M22 12c0-5.522-4.477-10-10-10-1.065 0-2.098.166-3.051.47l1.564 1.564A8 8 0 0112 4c4.418 0 8 3.582 8 8h-2z"
          ></path>
        </svg>
      </div>
    );
  }

```

Lastly we have a simple button and input interfaces for signing in and submitting signature requests!

```typescript

  return (
   <div className="flex flex-col items-center justify-center min-h-screen py-2 bg-white text-black">
      <div
        className={`text-2xl font-bold mb-8 ${
          authenticated ? "text-green-500" : "text-red-500"
        }`}
      >
        {authenticated ? "Authenticated" : "Not authenticated"}
      </div>
      <div className="text-center">
        <h1 className="text-3xl font-bold underline">
          Passport Protocol with Clerk Auth Quickstart
        </h1>
        <p className="mt-2 text-lg">
          This is a quickstart guide for the Passport Protocol SDK.
        </p>

        <div className="flex flex-col mt-4 space-y-4">
          {authenticated ? (
            <>
              <div className="flex flex-col space-y-4">
                <div className="flex items-center justify-between">
                  <div className="font-bold">Address</div>
                  <div>{address}</div>
                </div>
              </div>

              {messageSignature && (
                <div className="flex flex-col space-y-4 max-w-[60ch] break-words">
                  <div className="font-bold">Message Signature</div>
                  <div>{messageSignature.signature}</div>
                </div>
              )}

              <input
                value={message}
                onChange={(e) => setMessage(e.target.value)}
                className="border border-1 rounded p-2 border-black mb-4 ml-2 text-center"
                placeholder="Message to sign"
              />
              <button
                onClick={async () => await delegatedSignMessage(message)}
                disabled={signMessageLoading}
                className="border border-1 rounded p-2 border-black mb-4 ml-2"
              >
                {signMessageLoading ? "Signing..." : "Sign Message"}
              </button>
            </>
          ) : (
            <div className="mb-12 flex flex-col space-y-2 mt-8">
              <SignUpButton
                mode="modal"
                afterSignInUrl="/auth/callback"
                afterSignUpUrl="/auth/callback"
              >
                <button className="border border-1 rounded p-2 border-black mb-4 w-full">
                  Sign Up / In With Clerk
                </button>
              </SignUpButton>
              <SignOutButton>
                <button className="border border-1 rounded p-2 border-black mb-4 w-full">
                  Sign Out (Clear Cache)
                </button>
              </SignOutButton>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

```

### Complete Setup

Now with all of this setup we can setup our UI too, so the overall setup looks as below. In the final part of our setup, we've created the UI layer to interact with the above functions. We have buttons to register and authenticate, which dynamically interact with the state, to show loading states, as well as authenticated states, and finally when a message is signed, the user is also able to see the signed message signature.\
\
Please refer to <https://github.com/0xpass/passport-clerk-quickstart> for the complete setup.

You should be able to clone, update environment variable and run the example in less than a minute.

<figure><img src="/files/PFXHDuHUbol6qM4BUpMy" alt=""><figcaption></figcaption></figure>


# Lambda Quickstart

This quick start guide will walk you through how to quickly get setup with the Passport SDK, register and authenticate users, and start signing messages and transactions. You can skip to the [#complete-setup](#complete-setup "mention"), and then follow the section step-by-step where each code snippet will be explained. You can also quickly pull the completed repository here <https://github.com/0xpass/lambda-quickstart> and follow along.

For a deep dive into exactly how Lambda's work and are structured, you can follow the[Programmability](/programmability/overview) guide, alongside the quickstart.&#x20;

### Project setup

First we'll setup a Next.js project, with tailwind, we can do this with the following command, and walk through the configuration wizard, making sure to chose the app-router, and tailwind.

```bash
npx create-next-app@latest
```

### Setup and Dependencies

Firstly, we'll ensure we have all the requires dependencies. So we're going to install the Passport SDK **`@0xpass/passport`** to interact with Passport protocol to create and execute our Lambda, and  **`@0xpass/webauthn-signer`** to handle our passkey registration and authentication, finally **`@textea/json-viewer`** so that we can better see our lambda config in the UI.&#x20;

{% tabs %}
{% tab title="npm" %}

```bash
npm install @0xpass/passport @0xpass/webauthn-signer @textea/json-viewer
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm install @0xpass/passport @0xpass/webauthn-signer @textea/json-viewer
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn add @0xpass/passport @0xpass/webauthn-signer @textea/json-viewer
```

{% endtab %}
{% endtabs %}

Firstly let's setup a **`usePassport`** hook, which gives us an easy way to access our **`Passport`** instance.&#x20;

```typescript
import { useRef } from "react";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { Network, Passport } from "@0xpass/passport";

export function usePassport(scopeId: string) {
  const signerRef = useRef<WebauthnSigner | null>(null);
  const passportRef = useRef<Passport | null>(null);

  if (!signerRef.current) {
    signerRef.current = new WebauthnSigner({
      rpId: process.env.NEXT_PUBLIC_RP_ID!,
      rpName: "0xPass",
    });
  }

  if (!passportRef.current) {
    passportRef.current = new Passport({
      scopeId: scopeId,
      signer: signerRef.current,
      network: Network.TESTNET,
    });
  }

  return {
    passport: passportRef.current,
    signer: signerRef.current,
  };
}
```

Now in our **`page.tsx`** we can setup our state variables for, tracking registering, and authenticating users. We'll also use our **`Passport`** and **`WebauthnSigner`** instances, from the hook we just created. as well as our Alchemy url and a fallback provider, which we'll make use of when we want to signMessages with our **`WalletClient`**.

```typescript
"use client";
import { Fragment, useState } from "react";
import { usePassport } from "./hooks/usePassport";
import dynamic from "next/dynamic";

const JsonViewer = dynamic(
  () => import("@textea/json-viewer").then((mod) => mod.JsonViewer),
  { ssr: false }
);

export default function Page() {
  const [username, setUsername] = useState("");
  const [authenticated, setAuthenticated] = useState(false);
  const [authenticating, setAuthenticating] = useState(false);
  const [registering, setRegistering] = useState(false);
  const [authenticateSetup, setAuthenticateSetup] = useState(false);

  const [createLambdaLoading, setCreateLambdaLoading] = useState(false);
  const [lambdaListLoading, setlambdaListLoading] = useState(false);
  const [executeLambdaLoading, setExecuteLambdaLoading] = useState(false);
  const [stateLambdaId, setStateLambdaId] = useState<null | string>(null);
  const [lambdaList, setLambdaList] = useState<null | [any]>();
  const [selectedLambdaId, setSelectedLambdaId] = useState<null | string>(null);

  const [lambdaId, setLambdaId] = useState("");
  const [address, setAddress] = useState<string>();

  const userInput = {
    username: username,
    userDisplayName: username,
  };


  const { passport } = usePassport("07907e39-63c6-4b0b-bca8-377d26445172");
```

We use a **`useRef`** so that a new instance of **`WebauthnSigner`** and **`Passport`** aren't re-created during re-renders.

So we set up the functions for these as follows, we setup the **`register` , `authenticate`**

```typescript
const lambdaConfig = {
    authorization: {
      type: "none" as "none",
    },
    verifications: {
      count: 1,
    },
    envs: [],
    max_executions: 0,
    conditions: [
      {
        type: "code" as const,
        code: "if (Math.random() < 0.5) { return true; } else { return false; }",
        output_type: "integer" as const,
        substitution: true,
      },
    ],
    triggers: [],
    actions: {
      type: "personal_sign" as const,
      check: "",
      data: "0x000000",
      substitution: true,
    },
    postHook: [],
  };

  async function listLambdas() {
    setlambdaListLoading(true);
    try {
      const lambdas = await passport.listLambda();
      setLambdaList(lambdas.result);
      console.log(lambdas.result);
    } catch (err) {
      console.log(err);
    } finally {
      setlambdaListLoading(false);
    }
  }

  async function createLambda() {
    setCreateLambdaLoading(true);
    try {
      const result = await passport.createLambda({
        data: lambdaConfig,
      });

      console.log(result);

      alert(JSON.stringify(result.result));
    } catch (err) {
      console.log(err);
    } finally {
      setCreateLambdaLoading(false);
    }
  }

  async function executeLambda() {
    setExecuteLambdaLoading(true);
    try {
      const params = {
        data: {
          id: lambdaId ? lambdaId : stateLambdaId!,
          params: [],
        },
      };
      const result = await passport.executeLambda(params);
      if (result.result === "Condition not met") {
        alert("Ooops, probability wasn't on your side...");
      } else {
        alert(
          "Successful Signature Attempt:: " + JSON.stringify(result.result)
        );
      }
    } catch (err) {
      console.log(err);
    } finally {
      setExecuteLambdaLoading(false);
    }
  }

  async function register() {
    setRegistering(true);
    try {
      await passport.setupEncryption();
      const res = await passport.register(userInput);
      console.log(res);

      if (res.result.account_id) {
        setRegistering(false);
        setAuthenticating(true);
        await authenticate();
        setAuthenticating(false);
      }
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setRegistering(false);
      setAuthenticating(false);
    }
  }

  async function authenticate() {
    setAuthenticating(true);
    try {
      await passport.setupEncryption();
      const [_, address] = await passport.authenticate(userInput)!;

      console.log(address);
      setAddress(address);
      setAuthenticated(true);
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setAuthenticating(false);
    }
  }
```

### Complete Setup

Now with all of this setup we can setup our UI too, so the overall setup looks as below. In the final part of our setup, we've created the UI layer to interact with the above functions. We have buttons to register and authenticate, which dynamically interact with the state, to show loading states, as well as authenticated states. We also have our lambda configuration, as well as a list of toggle-able lambda's that we create where we can see more about their details, whether they've been executed, how many times they've been executed, etc.&#x20;

```typescript
"use client";
import { Fragment, useState } from "react";
import { usePassport } from "./hooks/usePassport";
import dynamic from "next/dynamic";

const JsonViewer = dynamic(
  () => import("@textea/json-viewer").then((mod) => mod.JsonViewer),
  { ssr: false }
);

export default function Page() {
  const [username, setUsername] = useState("");
  const [authenticated, setAuthenticated] = useState(false);
  const [authenticating, setAuthenticating] = useState(false);
  const [registering, setRegistering] = useState(false);
  const [authenticateSetup, setAuthenticateSetup] = useState(false);

  const [createLambdaLoading, setCreateLambdaLoading] = useState(false);
  const [lambdaListLoading, setlambdaListLoading] = useState(false);
  const [executeLambdaLoading, setExecuteLambdaLoading] = useState(false);
  const [stateLambdaId, setStateLambdaId] = useState<null | string>(null);
  const [lambdaList, setLambdaList] = useState<null | [any]>();
  const [selectedLambdaId, setSelectedLambdaId] = useState<null | string>(null);

  const [lambdaId, setLambdaId] = useState("");
  const [address, setAddress] = useState<string>();

  const userInput = {
    username: username,
    userDisplayName: username,
  };

  const { passport } = usePassport("07907e39-63c6-4b0b-bca8-377d26445172");

  const lambdaConfig = {
    authorization: {
      type: "none" as "none",
    },
    verifications: {
      count: 1,
    },
    envs: [],
    max_executions: 0,
    conditions: [
      {
        type: "code" as const,
        code: "if (Math.random() < 0.5) { return true; } else { return false; }",
        output_type: "integer" as const,
        substitution: true,
      },
    ],
    triggers: [],
    actions: {
      type: "personal_sign" as const,
      check: "",
      data: "0x000000",
      substitution: true,
    },
    postHook: [],
  };

  async function listLambdas() {
    setlambdaListLoading(true);
    try {
      const lambdas = await passport.listLambda();
      setLambdaList(lambdas.result);
      console.log(lambdas.result);
    } catch (err) {
      console.log(err);
    } finally {
      setlambdaListLoading(false);
    }
  }

  async function createLambda() {
    setCreateLambdaLoading(true);
    try {
      const result = await passport.createLambda({
        data: lambdaConfig,
      });

      console.log(result);

      alert(JSON.stringify(result.result));
    } catch (err) {
      console.log(err);
    } finally {
      setCreateLambdaLoading(false);
    }
  }

  async function executeLambda() {
    setExecuteLambdaLoading(true);
    try {
      const params = {
        data: {
          id: lambdaId ? lambdaId : stateLambdaId!,
          params: [],
        },
      };
      const result = await passport.executeLambda(params);
      if (result.result === "Condition not met") {
        alert("Ooops, probability wasn't on your side...");
      } else {
        alert(
          "Successful Signature Attempt:: " + JSON.stringify(result.result)
        );
      }
    } catch (err) {
      console.log(err);
    } finally {
      setExecuteLambdaLoading(false);
    }
  }

  async function register() {
    setRegistering(true);
    try {
      await passport.setupEncryption();
      const res = await passport.register(userInput);
      console.log(res);

      if (res.result.account_id) {
        setRegistering(false);
        setAuthenticating(true);
        await authenticate();
        setAuthenticating(false);
      }
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setRegistering(false);
      setAuthenticating(false);
    }
  }

  async function authenticate() {
    setAuthenticating(true);
    try {
      await passport.setupEncryption();
      const [_, address] = await passport.authenticate(userInput)!;

      console.log(address);
      setAddress(address);
      setAuthenticated(true);
    } catch (error) {
      console.error("Error registering:", error);
    } finally {
      setAuthenticating(false);
    }
  }

  return (
    <div className="flex flex-col items-center justify-center min-h-screen py-2 bg-white text-black">
      <div
        className={`text-2xl font-bold mb-8 ${
          authenticated ? "text-green-500" : "text-red-500"
        }`}
      >
        {authenticated ? "Authenticated" : "Not authenticated"}
      </div>
      <div className="text-center">
        <h1 className="text-3xl font-bold underline">
          Passport Lambda Quickstart
        </h1>
        <p className="mt-2 text-lg">
          This is a quickstart guide for Passport Lambda's
          {authenticated ? (
            <p className="text-xs text-center mt-8 max-w-[100ch] mb-10">
              You can create executable lambda's based on your lambda config
              below, once you create a lambda you can either execute your active
              'state' lambda, or list your lambda ID's to pick an ID to execute.
              You can click the lambda ids to, toggle the lambda's to see their
              full configuration and status', you'll need to click 'list
              lambdas' again to see any updates after execution
            </p>
          ) : (
            <p className="text-xs mt-8">
              Register / Sign In to start playing aroud with Passport Lambda's
            </p>
          )}
        </p>

        <div className="mt-4 space-y-4">
          {authenticated ? (
            <>
              <div className="flex flex-col mb-12">
                <div className="flex items-center justify-center space-x-6">
                  <div className="font-bold">Address</div>
                  <div>{address}</div>
                </div>
              </div>

              <div className="flex flex-row">
                <div className="w-full">
                  <JsonViewer
                    displayDataTypes={false}
                    theme="light"
                    displaySize={true}
                    rootName={false}
                    value={lambdaConfig}
                  />
                </div>

                <div className="flex flex-col w-full">
                  <div className="mb-3 space-y-2">
                    {lambdaList?.map((lambda) => (
                      <Fragment key={lambda.id}>
                        <div
                          className="text-sm cursor-pointer"
                          onClick={() =>
                            setSelectedLambdaId(
                              selectedLambdaId === lambda.id ? null : lambda.id
                            )
                          }
                        >
                          {lambda.id}
                        </div>
                        {selectedLambdaId === lambda.id && (
                          <JsonViewer
                            displayDataTypes={false}
                            theme="light"
                            defaultInspectDepth={0}
                            displaySize={true}
                            rootName={false}
                            value={lambda}
                          />
                        )}
                      </Fragment>
                    ))}
                  </div>
                  <button
                    onClick={async () => await listLambdas()}
                    className="border border-1 rounded p-2 border-black mb-4 ml-2"
                  >
                    {lambdaListLoading ? "Listing Lambdas..." : "List Lambdas"}
                  </button>

                  <button
                    onClick={async () => await createLambda()}
                    disabled={createLambdaLoading}
                    className="border border-1 rounded p-2 border-black mb-4 ml-2"
                  >
                    {createLambdaLoading
                      ? "Creating Lambda..."
                      : "Create Lambda"}
                  </button>

                  <input
                    value={lambdaId}
                    onChange={(e) => setLambdaId(e.target.value)}
                    className="border border-1 rounded p-2 border-black mb-4 ml-2 text-center"
                    placeholder="Lambda to Execute"
                  />

                  <button
                    onClick={async () => await executeLambda()}
                    disabled={executeLambdaLoading}
                    className="border border-1 rounded p-2 border-black mb-4 ml-2"
                  >
                    {executeLambdaLoading
                      ? "Executing Lambda..."
                      : "Execute Lambda"}
                  </button>
                </div>
              </div>
            </>
          ) : (
            <form
              onSubmit={async (e) => {
                e.preventDefault();
                if (authenticateSetup) {
                  await authenticate();
                } else {
                  register();
                }
              }}
            >
              <div className="mb-12 flex flex-col space-y-2 mt-8">
                <input
                  value={username}
                  onChange={(e) => setUsername(e.target.value)}
                  className="border border-1 rounded p-2 border-black mb-4 ml-2 text-center"
                  placeholder="Enter unique username"
                />
                <button
                  className="border border-1 rounded p-2 border-black mb-4 ml-2"
                  type="submit"
                  disabled={registering || authenticating}
                >
                  {authenticateSetup
                    ? authenticating
                      ? "Authenticating..."
                      : "Authenticate"
                    : registering
                    ? "Registering..."
                    : authenticating
                    ? "Authenticating..."
                    : "Register"}
                </button>

                <span
                  onClick={() => setAuthenticateSetup(!authenticateSetup)}
                  className="cursor-pointer"
                >
                  {authenticateSetup
                    ? "Register a Passkey?"
                    : "Already have a passkey?"}
                </span>
              </div>
            </form>
          )}
        </div>
      </div>
    </div>
  );
}
```


# Overview

Authentication is configured via developer defined scopes, where developers can describe policies, that determine things such as access control, and which authentication methods users will be permitted to use to login and interact with their application.

Passport currently supports the following types of authentication methods, all governed by scopes.&#x20;

| Authentication Method                | Description                                                                                                                                                                                                                                                                               | Status                                 |
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| [Passkeys](/authentication/passkeys) | <ul><li>Passkeys are <strong>user owned</strong> and support the WebAuthn standard. </li><li>The user can directly interact with the Passport nodes instead of going through any third-party/indemediary or the developer's own authentication systems. </li></ul>                        | <mark style="color:green;">Live</mark> |
| **Developer Owned**                  | <ul><li>Developer Owned auth supports any third-party authentication provider or the developer's own auth systems. </li><li>This method will let you bring any custom authentication method or flow of your choice and use Passport just for generating and managing key shares</li></ul> | <mark style="color:green;">Live</mark> |
| **OAuth**                            | <ul><li>Support for OAuth directly through enclaves on the Passport network</li></ul>                                                                                                                                                                                                     | Scheduled                              |
| **Email**                            | <ul><li>Support for OAuth directly through enclaves on the Passport network</li></ul>                                                                                                                                                                                                     | Scheduled                              |

You can first get started by learning how to [configure your scope](/authentication/configuring-your-scope) with the Passport CLI, once you've done that you'll be ready to start registering and authenticating users.


# Configuring your scope

## Introduction&#x20;

Scopes within the Passport Protocol act as programmable key management namespaces / configurations. By creating a scope you can:

* **Organise**: Keep your authentication methods and settings arranged in a clear way.
* **Control**: Set specific permissions and policies for each scope.
* **Customise**: Pick from authentication methods like OAuth, 2FA or more, that suit your needs.

## Setup&#x20;

Install `passport-scope-cli`

{% tabs %}
{% tab title="npm" %}

<pre class="language-bash"><code class="lang-bash"><strong>npm install -g passport-scope-cli
</strong></code></pre>

{% endtab %}

{% tab title="yarn" %}

```bash
yarn global add passport-scope-cli
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm install -g passport-scope-cli
```

{% endtab %}
{% endtabs %}

After installation, try `passport-scope` in your terminal to see if it is installed:

```bash
% passport-scope
Usage: passport-scope [options] [command]
```

Available Commands

* `-V, --version`: output the version number
* `-h, --help`: display help for command
* `create [options]`: Create a new scope based on the provided configuration.

## Commands

### **Generate Keys**

* Create a new keys for your scope if you haven't created one already.
* This should create two files
  * `<KEY_NAME>_pub.der`
  * `<KEY_NAME>_priv.der`

{% code overflow="wrap" %}

```bash
passport-scope generate-keys --name <KEY_NAME>
```

{% endcode %}

### **Create Scope**:

* This method creates a new scope based on the provided configuration file.
* Upon execution, you should receive a `scope_id` as output.
* The system generates a temporary random wallet for every scope.

{% code overflow="wrap" %}

```bash
passport-scope create --config-path ./<YOUR_CONFIG_FILE>.json --private-key ./<KEY_NAME>_priv.der --network testnet --verbose
```

{% endcode %}

**Note**: Always exercise caution with private keys. While the key isn't stored or used for any purpose other than signing, it's crucial to avoid using a private key that is already exposed with other services. Always opt for a freshly key pair dedicated solely to managing scopes.

Detailed configuration structures are as follows:

| Option        | Description                                                                                            |
| ------------- | ------------------------------------------------------------------------------------------------------ |
| --config-path | Path of the scope configuration content                                                                |
| --network     | The network you'd like to use can be testnet / mainnet / localhost                                     |
| --private-key | Path of the private key that is going to be the owner of the scope. If not provided, a new key pair is |

## Scope Configuration

Define the authentication rules for the scopes you own in JSON format.&#x20;

#### Passkeys

Here's a simple structure for a scope supporting Passkeys:

```json
{
  "rp": {
    "id": "demo.0xpass.io",
    "origin": "https://demo.0xpass.io/",
    "name": "Text Relying Party"
  },
  "policies":[]
}
```

Here are the components of the scope config

* rp: configurations for webauthn relaying party.&#x20;
  * id: the domain of where the passkey is generated
  * origin: full url of the domain
  * name: human readable name for the domain

## Keep track of your Scope ID

Upon successful creation of the scopes, take note of the `scope_id`.&#x20;

This `scope_id` is essential for initializing the Passport instance. For a comprehensive integration guide, please consult the [**Quickstarts** and **Examples** sections](/guides-and-examples/quickstarts-and-examples).

## Updating a Scope

Updating a scope is same as creating a scope, except you specify a scope id.

{% code overflow="wrap" %}

```bash
passport-scope update --scope-id ed5fdb5c-53f3-4a0f-a7af-53b0f09121bb --config-path ./<YOUR_CONFIG_FILE>.json --private-key ./<KEY_NAME>_priv.der --network testnet --verbose
```

{% endcode %}

## Next Steps&#x20;

Once you have your scope ID, you can now proceed to the appropriate authentication method sections to continue with your integration.&#x20;

* [#passkeys](#passkeys "mention")


# Passkeys

Passport Protocol allows you to register and authenticate users using Passkeys, following the [WebAuthn specification](https://www.w3.org/TR/webauthn-2/#sctn-intro).

Passkeys are a "user owned" authentication method, tied to the users device authenticator, which can be their Face ID / Touch ID, their Chrome profile, or even an external authenticator such as a Yubikey.

The following guides will walk you through, how to register and authenticate users, with Passkeys, using both our TypeScript SDK, and our API.

[Register using SDK](/authentication/passkeys/registration/register-using-sdk)

[Authenticating with SDK](/authentication/passkeys/authentication/authenticating-with-sdk)

[Register using API](/authentication/passkeys/registration/register-using-api)

[Authenticating with API](/authentication/passkeys/authentication/authenticating-with-api)


# Registration

<figure><img src="/files/A2D3zy4p9FD7Kj7FfWzw" alt=""><figcaption><p>Passport Passkey Registration Flow</p></figcaption></figure>

The above gives a high level view on how Passkey Registration works with Passport. You can [Register using SDK](/authentication/passkeys/registration/register-using-sdk) to have most of these details abstracted away. Currently we only have a TypeScript SDK, so you can also [Register using API](/authentication/passkeys/registration/register-using-api) if preferred.


# Register using SDK

The `register` method is your entry to Passport Protocol. The `register` method generates a key, using a passkey with a unique username under your scope, you can read more about scopes and how to [configure your scope](/authentication/configuring-your-scope).

To use the `register` method you'll have to instantiate an instance of `Passport` from the SDK and simply call the register function with the relevant parameters

```typescript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scope_id: "insert_your_scope_id",
    signer: signer,
});

const userInput {
   username: "insert_username_here"
   userDisplayName: "insert_user_display_name_here"
}

await passport.setupEncryption(); 
await passport.register(userInput);
```

Here we set up a `Passport` instance and a `WebauthnSigner` we use to generate passkeys and signatures. We also set up a userInput, which contains a unique `username` attached to your scope, and a `userDisplayName` which allows users to chose how they'd like their passkey to be saved. The `setupEncryption` method is called to create a secure channel of communication with the protocol.

### registration parameters

<table><thead><tr><th width="247">Parameter</th><th width="218">Description</th><th>Example Value</th></tr></thead><tbody><tr><td>username</td><td>A unique username attached to developers scope. </td><td><code>alice</code></td></tr><tr><td>userDisplayName</td><td>A display name which allows users to chose how they'd like their passkey to be saved. </td><td><code>alice</code></td></tr></tbody></table>

#### registration Response

A successful response will return the following, an `account_id` and corresponding `identifier_hash`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "account_id": "account_id_here",
        "identifier_hash": "identifier_hash_here"
    },
    "id": 1
}
```


# Register using API

User registration with Passkeys is split into 2 functions / API requests [Initiate Registration](/authentication/passkeys/registration/register-using-api/initiate-registration) and [Complete Registration](/authentication/passkeys/registration/register-using-api/complete-registration).

The `initiateRegistration` method initiates the user registration process within a specific scope. It generates a registration challenge that the user must solve to proceed with their registration which occurs in `completeRegistration`.&#x20;

The `completeRegistration` method is the part of the authentication API that finalizes the user registration process. It takes encrypted user data and a registration challenge, verifies it, and if successful, returns an identifier for the user.


# Initiate Registration

To register a user with Passkeys using the API you first need to make sure you have the values for your request headers set up by following the [Unauthenticated Requests](/appendix/api-request-setup/unauthenticated-requests) setup guide.

Once you have your values for `x-scope-id` and `x-encrypted-key` setup. You can now initiate a user registration.&#x20;

The initiateRegistration method initiates the user registration process within a specific scope. It generates a registration challenge that the user must solve to proceed with their registration.&#x20;

### **HTTP Method**: POST

* [Headers](/appendix/api-request-setup/unauthenticated-requests)
  * X-Scope-Id: A UUID string representing the application scope.
  * X-Encrypted-Key: A string containing the encrypted key for secure communication.
* **Body**:
  * **encrypted\_user**: String - A base64-encoded string containing encrypted user data.

The `encrypted_user` is generated by RSA encrypting the user parameters with the non-encrypted AES key you generated when following [Unauthenticated Requests](/appendix/api-request-setup/unauthenticated-requests), and by using the following `aesEncrypt` function.

```typescript
const aesEncrypt = async (
  plainText: string,
  encryptionKey: BufferSource,
  keyFormat: "raw" = "raw",
  keyLength: number = 256
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }

  const encoder = new TextEncoder();
  const data = encoder.encode(plainText);
  let cryptoKey: CryptoKey;
  let encrypted: ArrayBuffer;

  try {
    cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
      "encrypt",
    ]);

    const iv = cryptoObj.getRandomValues(new Uint8Array(12)); // Initialization vector
    
    // Same encrypt function from "Unauthenticated Requests" guide.
    encrypted = await encrypt({ name: "AES-GCM", iv }, cryptoKey, data);

    const combined = new Uint8Array(iv.length + encrypted.byteLength);
    combined.set(iv, 0);
    combined.set(new Uint8Array(encrypted), iv.length);

    return btoa(String.fromCharCode.apply(null, combined));
  } catch (error) {
    console.error("AES-GCM Encryption error:", error);
    throw error;
  }
};
```

Now we can encrypt our user parameters and pass that value as our `encrypted_user` in our API request.

```typescript
const params = {
    username: "test_user",
    userDisplayName: "test_user"
}

// Same aesKey created with `generateAesKey`
const encrypted_user = await aesEncrypt(JSON.stringify(params), aesKey);
```

### Response Spec

* **challenge\_id**: String - A UUID that uniquely identifies the registration challenge.
* **encrypted\_creation\_challenge**: String - A base64-encoded string representing the encrypted challenge that the user must solve to proceed with registration.

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
x-scope-id: 123e4567-e89b-12d3-a456-426614174000
x-encrypted-key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==

{
    "jsonrpc": "2.0",
    "method": "initiateRegistration",
    "params": {
        "encrypted_user": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
    },
    "id": 1
}
```

### Response Example

```json
{
    "jsonrpc": "2.0",
    "result": {
        "challenge_id": "e0f8cbee-6d64-4a9b-af88-3d73a8b95b34",
        "encrypted_creation_challenge": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
    },
    "id": 1
}
```


# Complete Registration

To complete registration you'll need the same header values as used in [Initiate Registration](/authentication/passkeys/registration/register-using-api/initiate-registration). The completeRegistration method is the part of the authentication API that finalizes the user registration process. It takes encrypted user data and a registration challenge, verifies it, and if successful, returns an identifier for the user.

### **Request Spec**

**HTTP Method**: POST

* [Headers](/appendix/api-request-setup/unauthenticated-requests)
  * x-scope-id: A UUID string representing the application scope.
  * x-encrypted-key: A string containing the encrypted key for secure communication.
* **Body**:

  * encrypted\_attestation: A string containing the encrypted attestation object.

  The [Initiate Registration](/authentication/passkeys/registration/register-using-api/initiate-registration) flow returns an `encrypted_creation_challenge`  which we need to decrypt with the decryption method below, and then, create an attestation, which we then encrypt and send as part of our request.

<pre class="language-typescript"><code class="lang-typescript">const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;

<strong>const decrypt = async (algo, key, data) => {
</strong>  try {
    const decryptedResult = await cryptoObj.subtle.decrypt(algo, key, data);
    return decryptedResult;
  } catch (error) {
    console.error("Decryption error:", error);
    throw error;
  }
};

const aesDecrypt = async (
  cipherText: string,
  encryptionKey: BufferSource,
  keyFormat: "raw" = "raw",
  keyLength: number = 256
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }
  let cryptoKey: CryptoKey;
  let decryptedData: ArrayBuffer;

  try {
    const combined = Uint8Array.from(atob(cipherText), (c) => c.charCodeAt(0));
    const iv = combined.slice(0, 12);
    const encryptedData = combined.slice(12);

    cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
      "decrypt",
    ]);

    decryptedData = await decrypt({ name: "AES-GCM", iv }, cryptoKey, encryptedData);

    const decoder = new TextDecoder();
    return decoder.decode(new Uint8Array(decryptedData));
  } catch (error) {
    console.error("AES-GCM Decryption error:", error);
    throw error;
  }
};
</code></pre>

```typescript
const challenge_id = initRegResponse.result.challenge_id;
const credential_creation_opts = await aesDecrypt(
      initRegResponse.result.encrypted_creation_challenge,
      aesKeyt
 );
const cco_json = JSON.parse(cco_str);

// Once you have the credential creation options you can create a webauthn compatible 
// attestation / signature e.g by using the broswer navigator.credentials.create
// function

const attestation = navigator.credentials.create(cco_json);
```

You can then encrypt the attestation with your AES Key and send it as part of the request&#x20;

```typescript
const encrypted_attestation = await aesEncrypt(JSON.stringify(attestation), aesKey);
```

* encrypted\_user: A string containing the encrypted user data. This is the same encrypted\_user from [Initiate Registration](/authentication/passkeys/registration/register-using-api/initiate-registration)
* challenge\_id: A UUID string representing the challenge issued during initiation. This is the challenge\_id result  from [Initiate Registration](/authentication/passkeys/registration/register-using-api/initiate-registration)

### **Response Spec**

* **Success**:
  * account\_id: A UUID string that uniquely identifies the user's account.
  * identifier\_hash: A string representing the hash of the user's identifier.
* **Error**: An object containing error details.

### **Request Example**

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
x-scope-id: 123e4567-e89b-12d3-a456-426614174000
x-encrypted-key: jp6...yKg==

{
  "jsonrpc": "2.0",
  "method": "completeRegistration",
  "params": {
    "encrypted_attestation": "JZV...Ug==",
    "encrypted_user": "JZV...Ug==",
    "challenge_id": "765e4567-e89b-12d3-a456-426614174000"
  },
  "id": 1
}
```

### **Response Example**

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "result": {
    "account_id": "456e4567-e89b-12d3-a456-426614174000",
    "identifier_hash": "0x25e...1617"
  },
  "id": 1
}
```


# Authentication

## Two Methods of Passkey Authentication

**1. Session-Based Authentication**

In this method, you authenticate with passkeys once to obtain a time-limited JWT (JSON Web Token). This token can then be used for subsequent actions such as `personal_sign`, `sign_transaction`, and other secure actions. This method is efficient because it requires only one authentication step per session, reducing the need for repeated verifications.

**2. Direct Passkey Authentication for Each Request**

This method requires you to authenticate using a passkey with every single request. It is more secure since each request is independently authenticated, but it can be less efficient due to the repetitive nature of authentication.

{% hint style="info" %}
**If you are implementing the session-based authentication (Flow 1), follow the below guidance. For details on implementing the direct passkey authentication with each request (Flow 2), refer to the specific methods.**
{% endhint %}

<figure><img src="/files/SElf5gJHP68BkA27CMfn" alt=""><figcaption><p>Passport Passkey Authentication Flow</p></figcaption></figure>

The above gives a high level view on how Passkey Authentication works with Passport. You can follow[Authenticating with SDK](/authentication/passkeys/authentication/authenticating-with-sdk) to have most of these details abstracted away. Currently we only have a TypeScript SDK, so you can also follow [Authenticating with API](/authentication/passkeys/authentication/authenticating-with-api) if preferred.


# Authenticating with SDK

## Authenticate

Once you've created an account and keypair has been created for it, to now interact with the protocol, to sign messages and transactions you will first have to authenticate. For authentication the flow is more or less the same.

```typescript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});
s
const passport = new Passport({
    scope_id: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_username_here"
   userDisplayName: "insert_user_display_name_here"
}

await passport.setupEncryption();
const [authenticatedHeader, address] = await passport.authenticate(userInput);
```

The setup is the same we just call the authenticate function with the userInput.

The authenticate function returns two items, a header which we use to authenticate subsequent requests, and the address associated with the account

The **authenticatedHeader**

```json
{
    // When we call setupEncryption, it generates a random aes key for you. It is the encrypted version of AES key using our public RSA key
    "X-Encrypted-Key": "nAr0IMFWsvN8nGqF43s+kmQ+dkCJhCQwr58SQ+vK+QaAqhuKur+974CeLApUPg+MeM8lOQOfFlm8Bkqowg0w2oszUcUyFH2WE2iDQk2ZrdQVDusSzjgP2lCZjxFDUHK2kpoD1qjoPMgjOI1sOnc0Bd9jLbv0OKWcVm6u/+8pJrV7LXZ5df2BOdUg3xXCg2OS2UfnuXgYR6o10aC4m+FdTDwbDl6bnUox8zESDuCHM6WfioaQTGRMrPxyajENSrEpGwwB6369hlW0lxeR7Lz+YIGLNPpGsoBx6P2zZfaJ8/DcOd5LUXXXMZT4bGeQxuNHJmw2I8wgmznmJy1T54UTsA==",
    // JWT token encrypted with encryption key (aes key provided by you)
    "X-Encrypted-Session": "C2FjnsrFaGlm3OOGwCoBNqaX8tO1FqVwPK3qKKD8gu9U3ZDVzYG6go9pV2kgg4suU3GwdwAOAF7fd9ULwVuIVcASuxDiL5uZ8A+yXw233TXuRk1vr0q2ZeJTnRkOSV4dV9EAfeuYzUtCCfrHaa7LlE7IXfVGHQ3lxm5F7AUt+bm+Ttphq+4c3iTp9XHzFH5vIUfATvpj1w2bSwe/4R8viMpcDHcj/OGGpdj5X0yWnEshP2Y1hpXYFXs71QWUjGueGavyaeAJK81eKOvOf0wT8zi0ZJWKPNGV45FqB+9VvDXooyQVfzoPojnybMPE/oRjSvSazU9MMUMEInRE9BIoeztBrQeoVG65W6erq1viITYb0OsV75+PzKOESmnLhRuoyqOi3If5wXu+gGQzI2xmnsgoXZNlfiUmgPhQU05989sUHRHRDpbX/LDD03Jq6X4l8GEa5+WVsTFkP55iyIePVfoXYFwVihYCwtPFeQgJp76KeRKs7T5YSneBDpoR5M+Y7a6aDpepjgmLReBGR1uRKaEZooW/bUdtgpwXjr4C1HFderWC/aBt4Mr2ySehHPOspNgmXNr0vN0tFkjfFgAC2mykE5d9Bn4h3M4laT/gM2dpIZAgWAwesJjmVIXAJ3za6EbREyJesicEg/SlbzbbLIw1W+vKYwfQgCCxdGwv8qV1BIuVm4OihNf4akZz9A9K6SBOybnbSQACOAXmzN57VZ6d4CMJl8Vx1XU1YaPAktiMb83J2ahbfxPsEOy2amYjyg==",
    //The scope if you passed during initialization
    "X-Scope-Id": "your_scope_id",
    //The user input you passed in authenticate function encrypted with encryption key (aes key provided by you)
    "X-Encrypted-User": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
}
```

The **address**:

```json
0xb3be8fcdc1f2b2fab67e9ecdf93b513a7a2500c1
```

Now with these setup, we can start to sign messages and transactions.


# Authenticating with API

User authentication with Passkeys is split into 2 functions / API requests [Initiate Authentication](/authentication/passkeys/authentication/authenticating-with-api/initiate-authentication)and [Complete Authentication](/authentication/passkeys/authentication/authenticating-with-api/complete-authentication)

The `initiateAuthentication` method is used to start the authentication process for a user within a specific application or developer scope. It prepares the necessary authentication challenge and returns it to the client.

The `completeAuthentication` method is used to finalize the user authentication process. It takes encrypted user data and a challenge, verifies it, and returns a response that includes a session jwt token if the authentication is successful.


# Initiate Authentication

To use `initiateAuthentication` method via the API you first need to make sure you have the values for your request headers set up by following the [Unauthenticated Requests](/appendix/api-request-setup/unauthenticated-requests) setup guide.

Once you have your values for `x-scope-id` and `x-encrypted-key` setup. You can now initiate a user authentication.&#x20;

**HTTP Method**: POST

* [**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll):
  * **X-Scope-Id**: A UUID string representing the application scope.
  * **X-Encrypted-Key**: A string containing the encrypted key for secure communication.
  * **X-Encrypted-User**: The user input encrypted using the encryption key
* **Body**:

  * **regenerate\_seed**: A boolean indicating whether to regenerate the seed for the session.
  * **encrypted\_user**: A string representing the encrypted user information.

  The `encrypted_user` is generated by RSA encrypting the user parameters with the non-encrypted AES key you generated when following [Unauthenticated Requests](/appendix/api-request-setup/unauthenticated-requests), and by using the following `aesEncrypt` function.

```typescript
const aesEncrypt = async (
  plainText: string,
  encryptionKey: BufferSource,
  keyFormat: "raw" = "raw",
  keyLength: number = 256
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }

  const encoder = new TextEncoder();
  const data = encoder.encode(plainText);
  let cryptoKey: CryptoKey;
  let encrypted: ArrayBuffer;

  try {
    cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
      "encrypt",
    ]);

    const iv = cryptoObj.getRandomValues(new Uint8Array(12)); // Initialization vector
    
    // Same encrypt function from "Unauthenticated Requests" guide.
    encrypted = await encrypt({ name: "AES-GCM", iv }, cryptoKey, data);

    const combined = new Uint8Array(iv.length + encrypted.byteLength);
    combined.set(iv, 0);
    combined.set(new Uint8Array(encrypted), iv.length);

    return btoa(String.fromCharCode.apply(null, combined));
  } catch (error) {
    console.error("AES-GCM Encryption error:", error);
    throw error;
  }
};
```

Now we can encrypt our user parameters and pass that value as our `encrypted_user` in our API request.

```typescript
const params = {
    username: "test_user",
    userDisplayName: "test_user"
}

// Same aesKey created with `generateAesKey`
const encrypted_user = await aesEncrypt(JSON.stringify(params), aesKey);
```

### Response Spec

* **challenge\_id**: A unique identifier for the authentication challenge.
* **encrypted\_request\_challenge**: A string representing the encrypted challenge that the user must respond to.

### Request Example

<pre class="language-http"><code class="lang-http">POST / HTTP/1.1
Host: https://tiramisu.0xpass.io
Content-Type: application/json
X-Scope-Id: 123e4567-e89b-12d3-a456-426614174000
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
<strong>X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
</strong>{
  "jsonrpc": "2.0",
  "method": "initiateAuthentication",
  "params": {
    "regenerate_seed": true,
    "encrypted_user": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
  },
  "id": 1
}
</code></pre>

### Response Example

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "result": {
    "challenge_id": "456e4567-e89b-12d3-a456-426614174000",
    "encrypted_request_challenge": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
  },
  "id": 1
}
```


# Complete Authentication

To complete registration you'll need the same header values as used in [Initiate Authentication](/authentication/passkeys/authentication/authenticating-with-api/initiate-authentication)

### **Request Spec**

**HTTP Method**: POST

* [**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll):
  * **X-Scope-Id**: A UUID string representing the application scope.
  * **X-Encrypted-Key**: A string containing the encrypted key for secure communication.
  * **X-Encrypted-User**: The user input encrypted using the encryption key
* **Body**:
  * **encrypted\_assertion:** A string containing the encrypted user assertion data.

To create an encrypted\_assertion, first have to decrypt the `encrypted_request_challenge` from the response in [Initiate Authentication](/authentication/passkeys/authentication/authenticating-with-api/initiate-authentication), with the following functions.&#x20;

<pre class="language-typescript"><code class="lang-typescript">const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;

<strong>const decrypt = async (algo, key, data) => {
</strong>  try {
    const decryptedResult = await cryptoObj.subtle.decrypt(algo, key, data);
    return decryptedResult;
  } catch (error) {
    console.error("Decryption error:", error);
    throw error;
  }
};

const aesDecrypt = async (
  cipherText: string,
  encryptionKey: BufferSource,
  keyFormat: "raw" = "raw",
  keyLength: number = 256
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }
  let cryptoKey: CryptoKey;
  let decryptedData: ArrayBuffer;

  try {
    const combined = Uint8Array.from(atob(cipherText), (c) => c.charCodeAt(0));
    const iv = combined.slice(0, 12);
    const encryptedData = combined.slice(12);

    cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
      "decrypt",
    ]);

    decryptedData = await decrypt({ name: "AES-GCM", iv }, cryptoKey, encryptedData);

    const decoder = new TextDecoder();
    return decoder.decode(new Uint8Array(decryptedData));
  } catch (error) {
    console.error("AES-GCM Decryption error:", error);
    throw error;
  }
};
</code></pre>

```typescript
const request_challenge_str = await aesDecrypt(
      initAuthResponse.result.encrypted_request_challenge,
      aesKey
);

const request_challenge_json = JSON.parse(request_challenge_str) 

// Once you have the credential creation options you can create a webauthn compatible 
// assertion / signature e.g by using the broswer navigator.credentials.get
// function

const assertion = navigator.credentials.get(request_challenge_json);
```

You can then encrypt the attestation with your AES Key and send it as part of the request&#x20;

```typescript
const encrypted_attestation = await aesEncrypt(JSON.stringify(assertion), aesKey);
```

* challenge\_id: A UUID string representing the unique challenge for this authentication request, returned from [Initiate Authentication](/authentication/passkeys/authentication/authenticating-with-api/initiate-authentication)

Encrypt user for headers.

```json
const params = {
    username: "test_user",
    userDisplayName: "test_user"
}

// Same aesKey created with `generateAesKey`
const encrypted_user = await aesEncrypt(JSON.stringify(params), aesKey);
```

### **Response Spec**

* **Body**:
  * encrypted\_jwt: A string containing the encrypted JSON Web Token (JWT) if authentication is successful.

### **Request Example**

```http
POST / HTTP/1.1
Host: https://tiramisu.0xpass.i
Content-Type: application/json
X-Scope-Id: 123e4567-e89b-12d3-a456-426614174000
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
  "jsonrpc": "2.0",
  "method": "completeAuthentication",
  "params": {
    "encrypted_assertion": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==",
    "challenge_id": "123e4567-e89b-12d3-a456-426614174000",
  },
  "id": 1
}
```

### **Response Example**

```http
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 128

{
  "jsonrpc": "2.0",
  "result": {
    "encrypted_jwt": "JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg=="
  },
  "id": 1
}
```


# Developer Owned Auth

Passport Protocol allows developers to bring their own or any third party authentication system into Passport using the network for only key management

The following guides will walk you through, how to register and authenticate users, with DOA, using both our TypeScript SDK, and our API.

{% content-ref url="/pages/ZlBBcS92pWMZxeTERSgq" %}
[Register using API](/authentication/developer-owned-auth/registration/register-using-api)
{% endcontent-ref %}

{% content-ref url="/pages/AEfM9ykoAYQpIdz4Tt1B" %}
[Authenticating with API](/authentication/passkeys/authentication/authenticating-with-api)
{% endcontent-ref %}

{% content-ref url="/pages/FXcOMN4gN8pvk9Pw8oWO" %}
[Register using SDK](/authentication/developer-owned-auth/registration/register-using-sdk)
{% endcontent-ref %}

{% content-ref url="/pages/Qf0J8YaxUTiuPfSvQBwC" %}
[Broken mention](broken://pages/Qf0J8YaxUTiuPfSvQBwC)
{% endcontent-ref %}


# Registration

<figure><img src="/files/FMA84LjDIAxjbra9HUKs" alt=""><figcaption><p>Passport DOA Registration Flow</p></figcaption></figure>

The above gives a high level view on how DOA Registration works with Passport. You can [Register using SDK](/authentication/developer-owned-auth/registration/register-using-sdk) to have most of these details abstracted away. Currently we only have a TypeScript SDK, so you can also [Register using API](/authentication/developer-owned-auth/registration/register-using-api) if preferred.


# Register using SDK

The `delegateRegisterAccount` method is your entry to Passport Protocol. The `delegateRegisterAccount` method generates a key, using a unique email/username under your scope, you can read more about scopes and how to [configure your scope](/authentication/configuring-your-scope).

To use the `delegateRegisterAccount` method you'll have to instantiate an instance of `Passport` from the SDK and simply call the register function with the relevant parameters

{% hint style="info" %}
Private key used for KeySigner can be generated by following[Generating DOA Keys](/appendix/generating-doa-keys)
{% endhint %}

```typescript
import { Passport } from "@0xpass/passport";
import { KeySigner } from "@0xpass/key-signer";

const signer = new KeySigner(process.env.PRIVATE_KEY!, true);

const passport = new Passport({
    scope_id: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "johndoe@somemail.com"
}

await passport.setupEncryption(); 
await passport.delegatedRegisterAccount(userInput);
```

Here we set up a `Passport` instance and a `KeySigner` we use to sign the obtain the signature from your DOA. We also set up a userInput, which contains a unique `username` attached to your scope, and a `userDisplayName` which allows users to chose how they'd like their passkey to be saved. The `setupEncryption` method is called to create a secure channel of communication with the protocol.<br>

### registration parameters

<table><thead><tr><th width="247">Parameter</th><th width="218">Description</th><th>Example Value</th></tr></thead><tbody><tr><td>username</td><td>username is identifier which we use to uniquely identify user. It may have any value like email, phone number, random string, but it must be unique</td><td><code>johndoe@somemail.com</code></td></tr></tbody></table>

#### registration Response

A successful response will return the following, an `account_id` and corresponding `identifier_hash`

```json
{
    "jsonrpc": "2.0",
    "result": {
        "account_id": "account_id_here",
        "identifier_hash": "identifier_hash_here"
    },
    "id": 1
}
```


# Register using API

User registration with DOA is done using `deletegateRegistration` method

{% content-ref url="/pages/ooK7S6hXc4qImlG8sEpJ" %}
[Delegate Registration](/authentication/developer-owned-auth/registration/register-using-api/delegate-registration)
{% endcontent-ref %}


# Delegate Registration

To register a user with DOA using the API you first need to make sure you have the values for your request headers set up by following the [Unauthenticated Requests](/appendix/api-request-setup/unauthenticated-requests) setup guide.

Once you have your values for `X-Scope-Id, X-Encrypted-User` and `X-Encrypted-Key` setup, You can now initiate a delegated user registration.&#x20;

Post that, you would need your own unique private key which you would use for signing. Follow the below guide ot generate it.\
[Generating DOA Keys](/appendix/generating-doa-keys)

The delegateRegister method registers a specific user within a specific scope. It generates user blockchain account on the backend and returns `account_id` and `identifier_hash` back.

### **Request Spec**

**HTTP Method**: POST

* [Headers](/appendix/api-request-setup/unauthenticated-requests)
  * X-Scope-Id: A UUID string representing the application scope.
  * X-Encrypted-Key: A string containing the encrypted key for secure communication.
* **Body**:

  * encrypted\_credential: A JSON object carrying the attestation with its signature
  * encrypted\_user: User details json encrypted using aes key

<pre class="language-typescript"><code class="lang-typescript">const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;

<strong>const decrypt = async (algo, key, data) => {
</strong>  try {
    const decryptedResult = await cryptoObj.subtle.decrypt(algo, key, data);
    return decryptedResult;
  } catch (error) {
    console.error("Decryption error:", error);
    throw error;
  }
};

const aesDecrypt = async (
  cipherText: string,
  encryptionKey: BufferSource,
  keyFormat: "raw" = "raw",
  keyLength: number = 256
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }
  let cryptoKey: CryptoKey;
  let decryptedData: ArrayBuffer;

  try {
    const combined = Uint8Array.from(atob(cipherText), (c) => c.charCodeAt(0));
    const iv = combined.slice(0, 12);
    const encryptedData = combined.slice(12);

    cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
      "decrypt",
    ]);

    decryptedData = await decrypt({ name: "AES-GCM", iv }, cryptoKey, encryptedData);

    const decoder = new TextDecoder();
    return decoder.decode(new Uint8Array(decryptedData));
  } catch (error) {
    console.error("AES-GCM Decryption error:", error);
    throw error;
  }
};
</code></pre>

```typescript
const userDetails = {
   username: payload.emailAddress,
}
const encrypted_user = await aesEncrypt(JSON.stringify(userDetails), aesKey);

const privateKeyBase64 = "your_base_encoded_kkey";

function createSignature(data, privateKey) {
  const sign = crypto.createSign('SHA256');
  sign.update(data);
  sign.end();
  return sign.sign(privateKey, 'base64');
}

function getPublicKey(privateKey) {
  const publicKey = crypto.createPublicKey(privateKey);
  const publicKeyDer = publicKey.export({ type: 'spki', format: 'der' });
  return publicKeyDer.toString('base64');
}

async function sign(options) {
  const privateKey = crypto.createPrivateKey({
    key: Buffer.from(privateKeyBase64, 'base64'),
    format: 'der',
    type: 'pkcs8',
  });

  const signature = createSignature(options, privateKey);
  const publicKeyId = getPublicKey(privateKey);

  return {
    kind: 'key', // Assuming 'Key' is the kind of credential you want to specify
    id: publicKeyId,
    clientData: options,
    signature: signature,
    algorithm: "SHA256",
  };
}

const signature = await sign(encrypted_user);

const attestation = await aesEncrypt(JSON.stringify(signature), aesKey);
```

### **Response Spec**

* **Success**:
  * account\_id: A UUID string that uniquely identifies the user's account.
  * identifier\_hash: A string representing the hash of the user's identifier.
* **Error**: An object containing error details.

### **Request Example**

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Scope-Id: 123e4567-e89b-12d3-a456-426614174000
X-Encrypted-Key: jp6...yKg==

{
  "jsonrpc": "2.0",
  "method": "delegatedRegistration",
  "params": {
    "encrypted_credential": { 
      KeySignature: {{attestation}}
    },  
    "encrypted_user": "JZV...Ug=="
  },
  "id": 1
}
```

### **Response Example**

```http
HTTP/1.1 200 OK
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "result": {
    "account_id": "456e4567-e89b-12d3-a456-426614174000",
    "identifier_hash": "0x25e...1617"
  },
  "id": 1
}
```


# Overview

Passport Protocol offers an EIP1193 interface for signing messages and transactions.&#x20;

By adhering to this standard, Passport ensures that users can use their familiar wallets and signing tools without needing to learn new interfaces or methods, which allows us to offer familiar integration with tools such as Viem, only requiring specific headers to be passed along with requests.

To abstract away any of the complexity required when setting up the required headers we also offer a TypeScript SDK, which handles all of this functionality in the background, for the simplest / quickest experience.&#x20;

To get started pick the signer guide that's appropriate for the type of authentication method you chose.&#x20;

| Authentication Method                                 | Description                                                                                                                                                                                                       | Status                                 |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
| [Passkeys Signer](/wallet-operations/passkeys-signer) | <ul><li>Make sure you've gone through the register and authentication flows for <a data-mention href="/pages/POvnwza6vSI0nbrYVACZ">/pages/POvnwza6vSI0nbrYVACZ</a>first so you can access the signers</li></ul>   | <mark style="color:green;">Live</mark> |
| [DOA Signer](/wallet-operations/doa-signer)           | <ul><li>Make sure you've gone through the register and authentication flows for <a data-mention href="/pages/d13tqxEfYDDHP81DcXiX">/pages/d13tqxEfYDDHP81DcXiX</a>  first so you can access the signers</li></ul> | <mark style="color:green;">Live</mark> |


# Passkeys Signer


# Sign Message

In this section, you will find comprehensive guides to implementing message signing using our SDK and API:

* [**Sign Message SDK**](/wallet-operations/passkeys-signer/sign-message/sign-message-sdk): Get started with our SDK  to integrate message signing into your application. The SDK flow abstracts away most interactions, making it the easiest way to get started
* [**Sign Message API**:](/wallet-operations/passkeys-signer/sign-message/sign-message-api) If you're not using TypeScript or prefer to use an API, you can directly make HTTP requests to sign messages.


# Sign Message SDK

signMessage allows you to generate a signature on a message.

To sign a message a user  / an account would need to have to have been register and authenticated  by going through  [Register using SDK](/authentication/passkeys/registration/register-using-sdk) flow.&#x20;

Once you have registered the user, you can choose one of the below 2 flows

## **Session-Based Authentication**

In order to use this flow, you must  [Authenticating with SDK](/authentication/passkeys/authentication/authenticating-with-sdk) first to obtain a JWT.  Here is a sample of how to use it

```javascript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { stringToHex } from "viem";
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
await passport.authenticate(userInput);

// Generate a signature
const signature = await passport.signMessage(stringToHex("hello world!"));
console.log(signature);
```

### signMessage Parameters

| Parameter | Description                    | Example Values                                                |
| --------- | ------------------------------ | ------------------------------------------------------------- |
| `message` | The message you'd like to sign | `68656c6c6f20776f726c64` (hex represenation of "hello world") |

#### signMessage Response

A successful response will return the following, a signature of the signed message by the authenticated account.

```json
{
    "jsonrpc": "2.0",
    "result": "signature_here",
    "id": 1
}
```

## **Direct Passkey Authentication**

Since you will be directly authenticating with Passkeys here, you don't need to go through authentication step. Here is a code sample:

```javascript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { stringToHex } from "viem";
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scope_id: "insert_your_scope_id",
    signer: signer
    allow_sessions: false
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
//This step is different for direct authentication
passport.setUserData(userInput)

// Generate a signature
const signature = await passport.signMessage(stringToHex("hello world!"));
console.log(signature);
```

### signMessage Parameters

| Parameter | Description                    | Example Values                                                |
| --------- | ------------------------------ | ------------------------------------------------------------- |
| `message` | The message you'd like to sign | `68656c6c6f20776f726c64` (hex represenation of "hello world") |

#### signMessage Response

A successful response will return the following, a signature of the signed message by the authenticated account.

```json
{
    "jsonrpc": "2.0",
    "result": "signature_here",
    "id": 1
}
```


# Sign Message API

## Introduction

The `personal_sign` method is used to sign a given message with the private key of a specified Ethereum address. This is a way to prove that the sender has control over the private key of the address, without revealing the key itself. It is widely used for authentication and message verification purposes.

To sign a message a user  / an account would need to have to have been register and authenticated  by going through [Register using API](/authentication/passkeys/registration/register-using-api) flow.&#x20;

Once you have registered the user, you can choose one of the below 2 flows

## **Session-Based Authentication**

### Request Spec

Follow the [Authenticating with API](/authentication/passkeys/authentication/authenticating-with-api) flow to obtain the session and then do the following HTTP request

[**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll)**:**

* X-Encrypted-Session: Session information for maintaining state or continuity.
* X-Encrypted-Key: Encrypted key for secure processing of the request.
* X-Encrypted-User: User details encrypted using encryption key

**Body:**

* Params: an array containing below items:
  * A string containing the message to sign, encoded in hexadecimal and prefixed with 0x.
  * A string representing the Ethereum address to sign the message with, prefixed with 0x.

### Response Spec

* Result: A string representing the hexadecimal signature of the message.

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Encrypted-Session: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "personal_sign",
  "params": [
    "0x7468697320697320612074657374206d657373616765",
    "0x00"
  ]
}
```

### Response Example

**Success Response:**

```json
{
  "jsonrpc": "2.0",
  "result": "0x66cc515557fc5b7a53de5ea02e6cd248f1500b1a1107e118c59739b35f1c696e48f89564f74dbd17883477b8f43b3e0454f20464071796c7d1363d5821aae7351b",
  "id": 2
}
```

**Error Response:**

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32603,
    "message": "Internal JSON-RPC error."
  },
  "id": 2
}
```

## **Direct Passkey Authentication**

### Request Spec

In order to use this approach, you must sign your User Input json using Passkey to obtain a signature.

[**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll)

* X-Encrypted-Key: Encrypted key for secure processing of the request.
* X-Encrypted-Webauthn-Signature: Webauthn signature encrypted using encryption key
* X-Encrypted-User: User details encrypted using encryption key

**Body:**

* Params: an array containing below items:
  * A string containing the message to sign, encoded in hexadecimal and prefixed with 0x.
  * A string representing the Ethereum address to sign the message with, prefixed with 0x.

### Response Spec

* Result: A string representing the hexadecimal signature of the message.

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Encrypted-Webauthn-Signature: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "personal_sign",
  "params": [
    "0x7468697320697320612074657374206d657373616765",
    "0x00"
  ]
}
```

### Response Example

**Success Response:**

```json
{
  "jsonrpc": "2.0",
  "result": "0x66cc515557fc5b7a53de5ea02e6cd248f1500b1a1107e118c59739b35f1c696e48f89564f74dbd17883477b8f43b3e0454f20464071796c7d1363d5821aae7351b",
  "id": 2
}
```

**Error Response:**

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32603,
    "message": "Internal JSON-RPC error."
  },
  "id": 2
}
```


# Sign Transaction

In this section, you will find comprehensive guides to implementing transaction signing using our SDK and API:

* [**Sign Transaction SDK**](/wallet-operations/passkeys-signer/sign-transaction/sign-transaction-sdk): Get started with our SDK  to integrate message signing into your application. The SDK flow abstracts away most interactions, making it the easiest way to get started
* [**Sign Transaction API**](/wallet-operations/passkeys-signer/sign-transaction/sign-transaction-api): If you're not using TypeScript or prefer to use an API, you can directly make HTTP requests to sign messages.


# Sign Transaction SDK

To sign a transaction a user  / an account would need to have to have been register and authenticated  by going through  [Register using SDK](/authentication/passkeys/registration/register-using-sdk) flow.

## **Session-Based Authentication**

In order to use this flow, you must  [Authenticating with SDK](/authentication/passkeys/authentication/authenticating-with-sdk) first to obtain a JWT.  Here is a sample of how to use it

```javascript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { stringToHex } from "viem";
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
await passport.authenticate(userInput);

// Transaction Can be of type legacy (0x0),
// EIP2930 (0x01) or EIP1559 (0x02)
const transaction = {
  nonce: "0",
  maxPriorityFeePerGas: "0x9184E72A", 
  maxFeePerGas: "0x9184E72A",
  to: "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
  gas: "0x7530", 
  value: "0x2386F26FC10000", 
  chainId: "0x7A69",
  type: "0x02"
}

// Generate a threshold signature
const signature = await passport.signTransaction(transaction);
console.log(signature); // This is an rlp encoded transaction signature
```

### signTransaction Parameters

<table><thead><tr><th>Parameter</th><th>Description</th><th>Example Values</th></tr></thead><tbody><tr><td><code>transaction</code></td><td>The transaction object to be signed, can be a Legacy, EIP2930, or EIP1559 transaction type</td><td><pre class="language-json"><code class="lang-json">{
  "nonce": "0",
  "maxPriorityFeePerGas": "0x9184E72A", 
  "maxFeePerGas": "0x9184E72A",
  "to": "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
  "gas": "0x7530", 
  "value": "0x2386F26FC10000", 
  "chainId": "0x7A69",
  "type": "0x02"
}
</code></pre></td></tr></tbody></table>

#### signTransaction Response

A successful response will return the following,  an RLP encoded transaction signature from the authenticated account that can be executed as a raw transaction.

```json
{
    "jsonrpc": "2.0",
    "result": "signed_transaction_here",
    "id": 1
}
```

## **Direct Passkey Authentication**

Since you will be directly authenticating with Passkeys here, you don't need to go through authentication step. Here is a code sample:

```javascript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";
import { stringToHex } from "viem";
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scope_id: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
//This step is different for direct authentication
passport.setUserData(userInput)

// Transaction Can be of type legacy (0x0),
// EIP2930 (0x01) or EIP1559 (0x02)
const transaction = {
  nonce: "0",
  maxPriorityFeePerGas: "0x9184E72A", 
  maxFeePerGas: "0x9184E72A",
  to: "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
  gas: "0x7530", 
  value: "0x2386F26FC10000", 
  chainId: "0x7A69",
  type: "0x02"
}

// Generate a threshold signature
const signature = await passport.signTransaction(transaction);
console.log(signature); // This is an rlp encoded transaction signature
```

### signTransaction Parameters

<table><thead><tr><th>Parameter</th><th>Description</th><th>Example Values</th></tr></thead><tbody><tr><td><code>transaction</code></td><td>The transaction object to be signed, can be a Legacy, EIP2930, or EIP1559 transaction type</td><td><pre class="language-json"><code class="lang-json">{
  "nonce": "0",
  "maxPriorityFeePerGas": "0x9184E72A", 
  "maxFeePerGas": "0x9184E72A",
  "to": "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
  "gas": "0x7530", 
  "value": "0x2386F26FC10000", 
  "chainId": "0x7A69",
  "type": "0x02"
}
</code></pre></td></tr></tbody></table>

#### signTransaction Response

A successful response will return the following,  an RLP encoded transaction signature from the authenticated account that can be executed as a raw transaction.

```json
{
    "jsonrpc": "2.0",
    "result": "signed_transaction_here",
    "id": 1
}
```


# Sign Transaction API

## Introduction

The signTransaction method allows securely signing an Ethereum transaction within an authenticated session.

To sign a message a user  / an account would need to have to have been register and authenticated  by going through [Register using API](/authentication/passkeys/registration/register-using-api) flow.&#x20;

Once you have registered the user, you can choose one of the below 2 flows

## **Session-Based Authentication**

### Request Spec

Follow the [Authenticating with API](/authentication/passkeys/authentication/authenticating-with-api) flow to obtain the session and then do the following HTTP request

[**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll)**:**

* X-Encrypted-Session: Session information for maintaining state or continuity.
* X-Encrypted-Key: Encrypted key for secure processing of the request.
* X-Encrypted-User: User details encrypted using encryption key

**Parameters:**

* `params`: The transaction parameters as a TypedTransaction object.
  * `from` - The sender address
  * `nonce` - The transaction nonce
  * `maxPriorityFeePerGas` - Max tip paid to miner
  * `maxFeePerGas` - Max total fee willing to pay
  * `to` - Recipient address
  * `gas` - Gas limit
  * `value` - Amount of ETH to send
  * `chainId` - Network ID
  * `type` - EIP-2718 transaction type

**Returns:**

An RLP encoded transaction signature that can be executed as a raw transaction

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Encrypted-Session: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [
        {
            "from": "0x764904Df4B0e3eBabBEE902e356D9cA701e1fC70",
            "nonce": "0",
            "maxPriorityFeePerGas": "0x9184E72A", 
            "maxFeePerGas": "0x9184E72A",
            "to": "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
            "gas": "0x7530", 
            "value": "0x2386F26FC10000", 
            "chainId": "0x13881",
            "type": "0x02"
        }
    ],
    "id": 1
}
```

### Response Example

```json
{
    "jsonrpc": "2.0",
    "result": "0x02f8748301388180849184e72a849184e72a82753094b89ff4e9ad6b33f69153fa710f9849f51712eec4872386f26fc1000080c080a0997d192e9037357eb47ce92f62bc3eb40946952322588527cb2a8bcfee364ee2a038ca2627eb05d833fa0dd7b96ba2a3bdf09907ad95c1a7f2fc3e5d4af7779582",
    "id": "1"
}
```

## **Direct Passkey Authentication**

### Request Spec

In order to use this approach, you must sign your User Input json using Passkey to obtain a signature.

[**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll)

* X-Encrypted-Key: Encrypted key for secure processing of the request.
* X-Encrypted-Webauthn-Signature: Webauthn signature encrypted using encryption key
* X-Encrypted-User: User details encrypted using encryption key

**Parameters:**

* `params`: The transaction parameters as a TypedTransaction object.
  * `from` - The sender address
  * `nonce` - The transaction nonce
  * `maxPriorityFeePerGas` - Max tip paid to miner
  * `maxFeePerGas` - Max total fee willing to pay
  * `to` - Recipient address
  * `gas` - Gas limit
  * `value` - Amount of ETH to send
  * `chainId` - Network ID
  * `type` - EIP-2718 transaction type

**Returns:**

An RLP encoded transaction signature that can be executed as a raw transaction

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Encrypted-Webauthn-Signature: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [
        {
            "from": "0x764904Df4B0e3eBabBEE902e356D9cA701e1fC70",
            "nonce": "0",
            "maxPriorityFeePerGas": "0x9184E72A", 
            "maxFeePerGas": "0x9184E72A",
            "to": "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
            "gas": "0x7530", 
            "value": "0x2386F26FC10000", 
            "chainId": "0x13881",
            "type": "0x02"
        }
    ],
    "id": 1
}
```

### Response Example

```json
{
    "jsonrpc": "2.0",
    "result": "0x02f8748301388180849184e72a849184e72a82753094b89ff4e9ad6b33f69153fa710f9849f51712eec4872386f26fc1000080c080a0997d192e9037357eb47ce92f62bc3eb40946952322588527cb2a8bcfee364ee2a038ca2627eb05d833fa0dd7b96ba2a3bdf09907ad95c1a7f2fc3e5d4af7779582",
    "id": "1"
}
```


# DOA Signer


# Sign Message

In this section, you will find comprehensive guides to implementing message signing using our SDK and API:

* [**Sign Message SDK**](/wallet-operations/passkeys-signer/sign-message/sign-message-sdk): Get started with our SDK  to integrate message signing into your application. The SDK flow abstracts away most interactions, making it the easiest way to get started
* [**Sign Message API**:](/wallet-operations/passkeys-signer/sign-message/sign-message-api) If you're not using TypeScript or prefer to use an API, you can directly make HTTP requests to sign messages.


# Sign Message SDK

signMessage allows you to generate a signature on a message.

To sign a message a user  / an account would need to have to have been registered through  [Register using SDK](/authentication/developer-owned-auth/registration/register-using-sdk) flow.&#x20;

## **Direct Authentication**

Since you will be directly authenticating with DOA here, you don't need to go through authentication step. Here is a code sample:

```javascript
import { Passport } from "@0xpass/passport";
import { stringToHex } from "viem";
import { Passport } from "@0xpass/passport";
import { KeySigner } from "@0xpass/key-signer";

const signer = new KeySigner(process.env.PRIVATE_KEY!, true);

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer,
    allowSessions: false
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
//This step is different for direct authentication
passport.setUserData(userInput)

// Generate a signature
const signature = await passport.signMessage(stringToHex("hello world!"));
console.log(signature);
```

### signMessage Parameters

| Parameter | Description                    | Example Values                                                |
| --------- | ------------------------------ | ------------------------------------------------------------- |
| `message` | The message you'd like to sign | `68656c6c6f20776f726c64` (hex represenation of "hello world") |

#### signMessage Response

A successful response will return the following, a signature of the signed message by the authenticated account.

```json
{
    "jsonrpc": "2.0",
    "result": "signature_here",
    "id": 1
}
```


# Sign Message API

## Introduction

The `personal_sign` method is used to sign a given message with the private key of a specified Ethereum address. This is a way to prove that the sender has control over the private key of the address, without revealing the key itself. It is widely used for authentication and message verification purposes.

To sign a message a user  / an account would need to have to have been register and authenticated  by going through [Register using API](/authentication/developer-owned-auth/registration/register-using-api) flow.&#x20;

## **Direct Authentication**

### Request Spec

In order to use this approach, you must sign your User Input json using DOA Key directly to obtain a signature.

[**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll)

* X-Encrypted-Key: Encrypted key for secure processing of the request.
* X-Encrypted-Key-Signature: Developer Key signature encrypted using encryption key
* X-Encrypted-User: User details encrypted using encryption key

**Body:**

* Params: an array containing below items:
  * A string containing the message to sign, encoded in hexadecimal and prefixed with 0x.
  * A string representing the Ethereum address to sign the message with, prefixed with 0x.

### Response Spec

* Result: A string representing the hexadecimal signature of the message.

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Encrypted-Key-Signature: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "personal_sign",
  "params": [
    "0x7468697320697320612074657374206d657373616765",
    "0x00"
  ]
}
```

### Response Example

**Success Response:**

```json
{
  "jsonrpc": "2.0",
  "result": "0x66cc515557fc5b7a53de5ea02e6cd248f1500b1a1107e118c59739b35f1c696e48f89564f74dbd17883477b8f43b3e0454f20464071796c7d1363d5821aae7351b",
  "id": 2
}
```

**Error Response:**

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": -32603,
    "message": "Internal JSON-RPC error."
  },
  "id": 2
}
```


# Sign Transaction

In this section, you will find comprehensive guides to implementing transaction signing using our SDK and API:

* [**Sign Transaction SDK**](/wallet-operations/passkeys-signer/sign-transaction/sign-transaction-sdk): Get started with our SDK  to integrate message signing into your application. The SDK flow abstracts away most interactions, making it the easiest way to get started
* [**Sign Transaction API**](/wallet-operations/passkeys-signer/sign-transaction/sign-transaction-api): If you're not using TypeScript or prefer to use an API, you can directly make HTTP requests to sign messages.


# Sign Transaction SDK

To sign a transaction a user  / an account would need to have to have been register and authenticated  by going through  [Register using SDK](/authentication/developer-owned-auth/registration/register-using-sdk) flow.

## **Direct Authentication**

Since you will be directly authenticating with DOA here, you don't need to go through authentication step. Here is a code sample:

```javascript
import { Passport } from "@0xpass/passport";
import { stringToHex } from "viem";
import { Passport } from "@0xpass/passport";
import { KeySigner } from "@0xpass/key-signer";

const signer = new KeySigner(process.env.PRIVATE_KEY!, true);

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
//This step is different for direct authentication
passport.setUserData(userInput)

// Transaction Can be of type legacy (0x0),
// EIP2930 (0x01) or EIP1559 (0x02)
const transaction = {
  nonce: "0",
  maxPriorityFeePerGas: "0x9184E72A", 
  maxFeePerGas: "0x9184E72A",
  to: "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
  gas: "0x7530", 
  value: "0x2386F26FC10000", 
  chainId: "0x7A69",
  type: "0x02"
}

// Generate a threshold signature
const signature = await passport.signTransaction(transaction);
console.log(signature); // This is an rlp encoded transaction signature
```

### signTransaction Parameters

<table><thead><tr><th>Parameter</th><th>Description</th><th>Example Values</th></tr></thead><tbody><tr><td><code>transaction</code></td><td>The transaction object to be signed, can be a Legacy, EIP2930, or EIP1559 transaction type</td><td><pre class="language-json"><code class="lang-json">{
  "nonce": "0",
  "maxPriorityFeePerGas": "0x9184E72A", 
  "maxFeePerGas": "0x9184E72A",
  "to": "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
  "gas": "0x7530", 
  "value": "0x2386F26FC10000", 
  "chainId": "0x7A69",
  "type": "0x02"
}
</code></pre></td></tr></tbody></table>

#### signTransaction Response

A successful response will return the following,  an RLP encoded transaction signature from the authenticated account that can be executed as a raw transaction.

```json
{
    "jsonrpc": "2.0",
    "result": "signed_transaction_here",
    "id": 1
}
```


# Sign Transaction API

## Introduction

The signTransaction method allows securely signing an Ethereum transaction within an authenticated session.

To sign a message a user  / an account would need to have to have been registered  by going through [Register using SDK](/authentication/developer-owned-auth/registration/register-using-sdk) flow.&#x20;

## **Direct Authentication**

### Request Spec

In order to use this approach, you must sign your User Input json using DOA to obtain a signature.

[**Headers**](broken://pages/6Ip1xrKh5rkgidowSGll)

* X-Encrypted-Key: Encrypted key for secure processing of the request.
* X-Encrypted-Key-Signature: Developer key signature encrypted using encryption key
* X-Encrypted-User: User details encrypted using encryption key

**Parameters:**

* `params`: The transaction parameters as a TypedTransaction object.
  * `from` - The sender address
  * `nonce` - The transaction nonce
  * `maxPriorityFeePerGas` - Max tip paid to miner
  * `maxFeePerGas` - Max total fee willing to pay
  * `to` - Recipient address
  * `gas` - Gas limit
  * `value` - Amount of ETH to send
  * `chainId` - Network ID
  * `type` - EIP-2718 transaction type

**Returns:**

An RLP encoded transaction signature that can be executed as a raw transaction

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Encrypted-Key-Signature: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: JZVjZw33OGoQDEMcbOdckx4TzspQEKP5j+iAGqf6b6gPleziY/Noyd4uW6KMSujq0HKP2Rb69p9Wi8ic5O8LZl9oTmmWk4op0CUKejqcV5DsNDp83PYzUg==
{
    "jsonrpc": "2.0",
    "method": "eth_signTransaction",
    "params": [
        {
            "from": "0x764904Df4B0e3eBabBEE902e356D9cA701e1fC70",
            "nonce": "0",
            "maxPriorityFeePerGas": "0x9184E72A", 
            "maxFeePerGas": "0x9184E72A",
            "to": "0xb89FF4E9AD6B33F69153fa710F9849f51712eEc4",
            "gas": "0x7530", 
            "value": "0x2386F26FC10000", 
            "chainId": "0x13881",
            "type": "0x02"
        }
    ],
    "id": 1
}
```

### Response Example

```json
{
    "jsonrpc": "2.0",
    "result": "0x02f8748301388180849184e72a849184e72a82753094b89ff4e9ad6b33f69153fa710f9849f51712eec4872386f26fc1000080c080a0997d192e9037357eb47ce92f62bc3eb40946952322588527cb2a8bcfee364ee2a038ca2627eb05d833fa0dd7b96ba2a3bdf09907ad95c1a7f2fc3e5d4af7779582",
    "id": "1"
}
```


# Viem Support

Passport Protocol uses an EIP 1193 compatible interface for signing messages, transaction and typed data. With this we've created a wallet client, which acts as a [JSON-RPC](https://viem.sh/docs/accounts/jsonRpc.html) account which allows you to leverage all of Viem's features.

## 1. Install the packages

{% tabs %}
{% tab title="npm" %}
`npm install viem @0xpass/passport-viem`&#x20;
{% endtab %}

{% tab title="pnpm" %}
`pnpm install viem @0xpass/passport-viem`&#x20;
{% endtab %}

{% tab title="yarn" %}
`yarn add viem @0xpass/passport-viem`&#x20;
{% endtab %}
{% endtabs %}

## 2. Choose your auth method

### Passkeys

{% tabs %}
{% tab title="npm" %}
`npm install @0xpass/webauthn-signer`&#x20;
{% endtab %}

{% tab title="pnpm" %}
`pnpm install @0xpass/webauthn-signer`&#x20;
{% endtab %}

{% tab title="yarn" %}
`yarn add @0xpass/webauthn-signer`&#x20;
{% endtab %}
{% endtabs %}

```typescript
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});
```

### DOA

{% tabs %}
{% tab title="npm" %}
`npm install @0xpass/key-signer`&#x20;
{% endtab %}

{% tab title="pnpm" %}
`pnpm install @0xpass/key-signer`&#x20;
{% endtab %}

{% tab title="yarn" %}
`yarn add @0xpass/key-signer`&#x20;
{% endtab %}
{% endtabs %}

```typescript
import { KeySigner } from "@0xpass/key-signer";

const signer = new KeySigner(process.env.PRIVATE_KEY!, true);
```

{% hint style="info" %}
In order to generate private key for DOA signer, follow [Generating DOA Keys](/appendix/generating-doa-keys)
{% endhint %}

## 3.  Create WalletClient

To create a wallet client, you'll need to have a registered and authenticated account, to setup a WalletClient with each signer you can follow the examples below.

#### Passkey Signer

```typescript
import { http, mainnet, WalletClient } from "viem/chains";
import { createPassportClient } from "@0xpass/passport-viem";
import { Passport } from "@0xpass/passport";

const signer: new WebauthnSigner({
  rpId: "rpId",
  rpName: "rpName",
})

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
const [authenticatedHeader] = await passport.authenticate(userInput);

const chain = mainnet;
const transport = http("any eth node endpoint");

// Create viem WalletClient using Passport
const client: WalletClient = await createPassportClient(
  authenticatedHeader,
  transport,
  chain
);
```

#### Developer Owned Auth Signer

```typescript
import { Passport } from "@0xpass/passport";
import { KeySigner } from "@0xpass/key-signer";
import { createPassportClient } from "@0xpass/passport-viem";
import { walletClientToSmartAccountSigner } from "permissionless";
import { http } from "viem";
import { mainnet } from "viem/chains";

const signer = new KeySigner(process.env.PRIVATE_KEY!, true)

const passport = new Passport({
  scopeId: "scope_id",
  signer: signer
});

const fallbackProvider = http("insert_alchemy_url");

await passport.setupEncryption();
await passport.delegatedRegisterAccount({ username: "test" });

passport.setUserData({ username: "test" });

const chain = mainnet;
const transport = http("any eth node endpoint");

const client = await createPassportClient(
  await passport.getDelegatedAuthenticatedHeaders(),
  transport,
  chain
);
```

## 4. Use Viem as usual

Here's an example of the viem wallet client created by Passport sending a transaction.

```typescript
const [account] = await client.getAddresses();
const transaction = await client.prepareTransactionRequest({
  account: account,
  to: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8",
  value: BigInt(1000000000000000),
  chain: mainnet,
});

client
  .signTransaction(transaction)
  .then((res) => alert(JSON.stringify(res)))
  .catch((err) => alert(JSON.stringify(err)));
```


# Overview

Passport Protocol, offer programmability in the from of what we call Lambda's. Lambdas are programmable conditions that can be used to specify signing and authentication logic for specific wallets.

You can use both on and off-chain data to provide specific signature conditions by simple use of APIs.  Examples of what is possible, using programmable actions:

* Sign my transaction when ETH prices reaches $3000 and submit to  blockchain.
* Send signature to specific API endpoint, if Date > 12th Jan, 2023
* Generate a signature based on smart contract call outputs

## Features

* **Off-Chain Compatibility**: Lambda Actions can pull in data from off-chain sources natively, without requiring the use of a third party oracle.
* **Run Arbitrary Code** - Execute any arbitrary code to determine whether to sign or not
* **Embeds with any workflow** - Post hooks allows the developers/ users to embed the automation within their workflow easily.


# Passport Lambda

Automate your access control or even your complete flow using Lambda's.

**Lambdas** can be registered with account owners as a json with Passport protocol.

The JSON has a very specific format (refer to example at the last).  In this section, we will dive deep into different components of the JSON .  Here is a rough overview of different components:

* **Authorization** - Specify who is allowed to allowed to run a lambda function using the "authorization" parameter. Options include "none" (anyone can trigger). More options will be available soon.
* **Triggers** - Specify how/when your lambda function gets executed. Currently two triggers are available - hook (by calling executeLambda endpoint with lambda id) or account (attach to your own account so it gets executed every time sign functions are called).  You can also use array of triggers.
* **Conditions** - Define a list of conditions that must be met for the lambda function to generate a signature. Conditions can be of type "fetch" (external API calls) or "code" (arbitrary Deno-compatible code execution).&#x20;
* **Max Executions** - Set the maximum number of executions allowed for the lambda function using the "max\_executions" parameter. A value of 0 allows infinite executions.
* **Envs** - Pass arbitrary environment variables to the lambda, using the "envs" array. These variables are composable and can be accessed by using "substitution"
* **Verifications** - Specify the number of independent verifiers required for the condition match using the "verifications" object. Currently, it defaults to 1.
* **Action** - Define the signature generation process using the "actions" object. Supported types include "personal\_sign" (signing hex data) and "eth\_signTransaction" (signing a transaction, coming soon).
* **Post Hook** - Specify a list of post-processing actions to be triggered after signature generation using the "postHook" array. These actions can include sending the signature to an API, triggering alerts, or submitting transactions.

Let's dive into each component in further detail, and walk through the process of building a Lambda JSON object.&#x20;

## Authorization

During the registration process for a lambda function, user can define who is allowed the trigger the lambda function. Please note that, "Triggering the function" != "Execution". Execution will be governed by conditions.

Authorization can be take many values such us:

* **None** - Anybody can trigger lambda.

<pre class="language-json5"><code class="lang-json5"><strong>"authorization": {
</strong>    "type": "none"
}
</code></pre>

* **Self -** Only owner can trigger the lambda.

```json
"authorization": {
    "type": "self"
}
```

* **Wallet** - Only provided wallet can trigger the lambda.

```json
"authorization": {
    "type": "wallet",
    "address": "0x10D64772Db984F63665cf64b4a1A358d377c68d1"
}
```

{% hint style="warning" %}
**Important Note**

In current release, only Authorization = None is active. Other 2 variants are coming soon.
{% endhint %}

## Triggers

What initiates the lambda execution. It can take the following values:

* **account** - Attach to your account and execute any time sign functions are called on your account

```json5
"triggers": [
  {
    "type": "account",
  }
]
```

* **hook -** Executes when called through executeLambda function/endpoint with respective lambda id.

```json
"triggers": [
  {
    "type": "hook",
  }
]
```

{% hint style="warning" %}
You can also use both triggers at the same time since trigger takes an array
{% endhint %}

## Verification

This accounts for how many independent verifiers of your condition match must be present for action to be executed.

```json
"verifications": {
  "count": 1
}
```

{% hint style="warning" %}
Currently, it is always defaulted to 1
{% endhint %}

## Max Executions

This variable controls how many times at max you wanna allow successful execution of your lambda function.

```json
"max_executions": 1
```

{% hint style="info" %}
If you wanna have infinite executions, mark it 0. It should be always >=0
{% endhint %}

## Envs

This allows you to pass any arbitrary environment variables that you want to pass into your runtime.

```json
"envs": ["dummy", 13, {"code": 2 }]
```

{% hint style="info" %}
You can use it via substitutions as <\<envs.0>>. 0 refers to the index in the array
{% endhint %}

## Conditions

Conditions govern criteria under which the lambda action is allowed to generate a signature.  You can pass a combination of conditions as an array.&#x20;

There are 2 important points to note:&#x20;

1. You can use outputs of previous conditions in any of the following conditions.
2. Last condition must return a boolean telling the lambda whether to generate signature or not

Each condition can be one of the 2 types:

1. **Fetch** - Use this type of condition to do any external API call (on-chain or off-chain) and return its response as output.&#x20;

{% code title="Fetch" %}

```json
{
    "type": "fetch",
    "endpoint": "http://api.xyz.com",
    "headers": {
        "content-type": "application/json"
    },
    "protocol": "GET", //can be GET,POST
    "body": {
        "count" : 1
    }, //pass whatever body content you need
    "substitution": false // whether to allow using of previous condition outputs
}
```

{% endcode %}

2. **Code -** Use this type of condition to execute any arbritrary deno compatible code (without online connectivity) and return its response as output.&#x20;

{% code title="Arbitrary Code" %}

```json
{
  "type": "code", 
  "code": "return 3+5;", // pass any arbritrary multi-line code as string
  "output_type": "integer", // ignore this - not used currently
  "substitution": false // whether to allow using of previous condition outputs
}
```

{% endcode %}

As you see above, you can also enable substitutions. Here is an example:

{% code title="Using Substitutions" %}

```json
[
    {
        "type": "code",
        "code": "return 3;",
        "output_type": "integer",
        "substitution": false
    },
    {
        "type": "code",
        "code": "return <<conditions.0>> === 3;", //substitution conditions.0 = output of 0th index of conditions
        "output_type": "integer",
        "substitution": true
    },
    {
        "type": "fetch",
        "endpoint": "http://api.xyz.com",
        "headers": {
            "content-type": "application/json"
        },
        "protocol": "GET", //can be GET,POST
        "body": {
            "count" : "<<inputs.0>>" //refers to the 0th input parameter passed during execution
        },
        "substitution": true 
    }
]
```

{% endcode %}

## Actions

Actions are responsible for the signature generation process. This are the equivalent of ERC-1193 operations to be performed using your wallet. Currently, the following 2 operations are possible

1. **personal\_sign**

```json
"actions": {
  "type": "personal_sign",
  "check": "", //ignore not used
  "data": "0x000000", //hex data to be signed
  "substitution": false //substition support coming soon
},
```

2. **eth\_signTransaction (Coming Soon)**

```json
"actions": {
  "type": "eth_signTransaction",
  "check": "", //ignore not used
  "data": {
  }, //transaction data 
  "substitution": false //not possible at this point
}
```

## Post Hook

After you have generated the signature, you may want to trigger any post process via an API call. This may be sending over the signature to an API, triggering a slack alert or even submitting a transaction. You can pass a list of post hooks to be triggered post signature generation.

{% code title="Fetch" %}

```json
[{
    "type": "fetch",
    "endpoint": "http://api.xyz.com",
    "headers": {
        "content-type": "application/json"
    },
    "protocol": "GET", //can be GET,POST
    "body": {
        "signature" : "<<action>>"
    }, //pass whatever body content you need
    "substitution": true // whether to allow using previous action output
}]
```

{% endcode %}

## Example

```json
{
    "jsonrpc": "2.0",
    "method": "lambda_new",
    "params": {
        "data": {
            "authorization": {
                "type": "none"
            },
            "verifications": {
                "count": 1
            },
            "triggers" : [
                {
                    "type": "account",
                },
                {
                    "type": "hook",
                },
            ]
            "conditions": [
                {
                    "type": "code",
                    "code": "return 3;",
                    "output_type": "integer",
                    "substitution": false
                },
                {
                    "type": "code",
                    "code": "return true;",
                    "output_type": "integer",
                    "substitution": false
                }
            ],
            "actions": {
                "type": "personal_sign",
                "check": "",
                "data": "0x000000",
                "substitution": true
            },
            "postHook": []
        }
    },
    "id": 3
}
```


# Lambda Functions


# Create Lambda

Allows the user to register a lambda function with Passport Protocol

In this section, you will find comprehensive guides to implementing transaction creating Lambda's using our SDK and API:

* [**Create Lambda SDK**](/programmability/lambda-functions/create-lambda/create-lambda-sdk): Get started with our SDK  to integrate create lambda's into your application. The SDK flow abstracts away most interactions, making it the easiest way to get started
* [**Create Lambda API**](/programmability/lambda-functions/create-lambda/create-lambda-api): If you're not using TypeScript or prefer to use an API, you can directly make HTTP requests to create lambda's.


# Create Lambda SDK

To register a lambda, a user  / an account would need to have to have been created ( [Registration](/authentication/passkeys/registration)) and have an associated session by going through the [Authenticating with SDK](/authentication/passkeys/authentication/authenticating-with-sdk) flow. Once you have the required details you can call the sign method by instantiating a Passport instance from the SDK as shown below.

```javascript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});


const userInput {
   username: "insert_username_here"
   userDisplayName: "insert_user_display_name_here"
}

await passport.setupEncryption(); 
await passport.authenticate(userInput);

const config = {
    "authorization": {
        "type": "none"
    },
    "verifications": {
        "count": 1
    },
    "triggers": [
       { "type": "hook"},
    ],
    "envs": [],
    "max_executions": 0,
    "conditions": [
        {
            "type": "code",
            "code": "if (Math.random() < 0.5) { return true; } else { return false; }",
            "output_type": "integer",
            "substitution": true
        }
    ],
    "actions": {
        "type": "personal_sign",
        "check": "",
        "data": "0x000000",
        "substitution": true
    },
    "postHook": []
}

// Generate a threshold signature
const lambda_uuid = await passport.createLambda({data:config});
console.log(lambda_uuid);
```

### createLambda Parameters

<table><thead><tr><th>Parameter</th><th>Description</th><th>Example Values</th></tr></thead><tbody><tr><td><code>data</code></td><td>Refer to <a href="/pages/wAckqo6WfxFU2S4vEPbE">Full Spec</a> for more info.</td><td><pre class="language-json"><code class="lang-json">{
    "authorization": {
        "type": "none"
    },
    "verifications": {
        "count": 1
    },
    "envs": [],
    "max_executions": 0,
    "conditions": [
        {
            "type": "code",
            "code": "if (Math.random() &#x3C; 0.5) { return true; } else { return false; }",
            "output_type": "integer",
            "substitution": true
        }
    ],
    "actions": {
        "type": "personal_sign",
        "check": "",
        "data": "0x000000",
        "substitution": true
    },
    "postHook": []
}
</code></pre></td></tr></tbody></table>

#### createLambda Response

A successful response will return a unique UUID required to execute the lambda function

```json
{
    "jsonrpc": "2.0",
    "result": "a23ef114-c5fb-41c6-b863-0781a3d10ee5",
    "id": 3
}
```


# Create Lambda API

The createLambda is a JSON-RPC endpoint that handles the creation of a new lambda function. It requires a lambda configuration as an input. If the creation is successful, it returns a unique identifier for the lambda required to execute it.

For instructions on how to setup your request headers you can follow [Authenticated Requests](/appendix/api-request-setup/authenticated-requests) guide

### Request Spec

**HTTP Method**: POST

* [**Headers**](/appendix/api-request-setup/authenticated-requests):
  * X-Encrypted-Session: Encrypted JWT signature for authentication.
  * X-Encrypted-Key: A string containing the encrypted key for secure communication.
  * X-Encrypted-User: User Input encrypted using Encryption Key
* **Body**:
  * **data**: JSON - A lambda configuration describing how the lambda works

### Response Spec

* **lambda\_uuid**: String - A UUID that uniquely identifies the lambda and is essential for executing it later.

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Encrypted-Session: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcK
{
    "jsonrpc": "2.0",
    "method": "createLambda",
    "params": {
        "data": {
            "authorization": {
                "type": "none"
            },
            "triggers": [
               { "type": "hook"},
            ],
            "verifications": {
                "count": 1
            },
            "envs": [],
            "max_executions": 0,
            "conditions": [
                {
                    "type": "code",
                    "code": "return true",
                    "output_type": "integer",
                    "substitution": true
                }
            ],
            "actions": {
                "type": "personal_sign",
                "check": "",
                "data": "0x000000",
                "substitution": true
            },
            "postHook": []
        }
    },
    "id": 3
}
```

### Response Example

Success:

```json
{
    "jsonrpc": "2.0",
    "result": "a23ef114-c5fb-41c6-b863-0781a3d10ee5",
    "id": 3
}
```

Error:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": 401,
    "message": "Unauthorized: Signature verification failed."
  },
  "id": 1
}
```


# Execute Lambda

Allows a user to execute the lambda function

In this section, you will find comprehensive guides to implementing transaction creating Lambda's using our SDK and API:

* [**Execute Lambda SDK**](/programmability/lambda-functions/execute-lambda/execute-lambda-sdk): Get started with our SDK  to execute lambda's into your application. The SDK flow abstracts away most interactions, making it the easiest way to get started
* [**Execute Lambda API**](/programmability/lambda-functions/execute-lambda/execute-lambda-api): If you're not using TypeScript or prefer to use an API, you can directly make HTTP requests to execute lambda's.


# Execute Lambda SDK

To execute a lambda, as of now, user need not authenticate. It can directly call for lambda execution provided it has the unique UUID.

```javascript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});

const request_body = {
    data: {
        "id": "15363182-f572-40ee-ba2a-efee4c8a3691",
        "params": []
    }
};

// Generate a threshold signature
const response = await passport.executeLambda(config);
console.log(response.result);
```

### executeLambda Parameters

<table><thead><tr><th>Parameter</th><th>Description</th><th>Example Values</th></tr></thead><tbody><tr><td><code>data</code></td><td>id = lambda_uuid obtained during creation,<br>params = list of any arbritrary inputs you want to pass during function execution. It can anything, a list of string, numbers, json objects or even mixed array.</td><td><pre class="language-json"><code class="lang-json">{
        "id": "15363182-f572-40ee-ba2a-efee4c8a3691",
        "params": []
}
</code></pre></td></tr><tr><td></td><td></td><td></td></tr></tbody></table>

#### executeLambda Response

A successful response will return a signature or Condition not met.

```json
{
    "jsonrpc": "2.0",
    "result": "0x9d73f5605320e17ab1eaa0e7d1c82df288fddbef1085bbc4d30707128b8dac135ef3207c349c522f407cc6e72740e2ee503c4086ce8d0096f665180e9d8f71ab1b",
    "id": 3
}
```


# Execute Lambda API

The executeLambda is a JSON-RPC endpoint that handles is used to execute a given lambda. It takes lambda\_uuid and params as inputs and returns an error or signature.

### Request Spec

**HTTP Method**: POST

* [**Headers**](/appendix/api-request-setup/unauthenticated-requests):
  * **N/A**
* **Body**:
  * **id**: String -> Unique Lambda UUID obtained during creaction
  * **params**: Array -> List of arbitrary inputs you want to pass during execution.

### Response Spec

* **result**: String -> Error message or Wallet Signature

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json

{
    "jsonrpc": "2.0",
    "method": "executeLambda",
    "params": {
        "data": {
            "id": "15363182-f572-40ee-ba2a-efee4c8a3691",
            "params": []
        }
    },
    "id": 3
}
```

### Response Example

Success:

```json
{
    "jsonrpc": "2.0",
    "result": "0x9d73f5605320e17ab1eaa0e7d1c82df288fddbef1085bbc4d30707128b8dac135ef3207c349c522f407cc6e72740e2ee503c4086ce8d0096f665180e9d8f71ab1b",
    "id": 3
}
```

Error:

```json
{
    "jsonrpc": "2.0",
    "result": "Condition not met",
    "id": 3
}
```


# List Lambda

View list of lambda functions registered by user

In this section, you will find comprehensive guides to implementing transaction creating Lambda's using our SDK and API:

* [**List Lambda SDK**](/programmability/lambda-functions/list-lambda/list-lambda-sdk): Get started with our SDK  to fetch lambda's into your application. The SDK flow abstracts away most interactions, making it the easiest way to get started
* [**List Lambda API**](/programmability/lambda-functions/list-lambda/list-lambda-api): If you're not using TypeScript or prefer to use an API, you can directly make HTTP requests to list lambda's.


# List Lambda SDK

To view the list of their registered lambdas, a user  / an account would need to have to have been created and have an associated session by going through the [Authenticating with SDK](/authentication/passkeys/authentication/authenticating-with-sdk) flow. Once you have the required details you can call the sign method by instantiating a Passport instance from the SDK as shown below.

```javascript
import { Passport } from "@0xpass/passport";
import { WebauthnSigner } from "@0xpass/webauthn-signer";

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_username_here"
   userDisplayName: "insert_user_display_name_here"
}

await passport.setupEncryption(); 
await passport.authenticate(userInput);


// Generate a threshold signature
const lambdas = await passport.listLambda();
console.log(lambdas);
```

#### listLambda Response

A successful response return list of lambda objects currently registered with user.

```json
{
    "jsonrpc": "2.0",
    "result": [
        {
            "id": "153634-f572-40ee-ba2a-efee345a3691",
            "config": {
                "actions": {
                    "data": "0x000000",
                    "substitution": true,
                    "type": "personal_sign"
                },
                "authorization": {
                    "type": "none"
                },
                "triggers": [
                   { "type": "hook"},
                ],
                "conditions": [
                    {
                        "code": "return true",
                        "output_type": "integer",
                        "substitution": true,
                        "type": "code"
                    }
                ],
                "envs": [],
                "max_executions": 0,
                "postHook": [],
                "verifications": {
                    "count": 1
                }
            },
            "status": "ready",
            "proof": null,
            "created_at": "2024-03-29T19:28:43",
            "updated_at": "2024-03-29T19:46:48",
            "total_executions": 2,
            "ok_executions": 2
        }
    ]
}
```


# List Lambda API

The listLambda is a JSON-RPC endpoint that handles is used to view all registered lambdas by a user. It doesn't take any input and returns list of all registered lambdas.

### Request Spec

**HTTP Method**: POST

* [**Headers**:](/appendix/api-request-setup/authenticated-requests)
  * X-Encrypted-Session: Encrypted JWT signature for authentication.
  * X-Encrypted-Key: A string containing the encrypted key for secure communication.
  * X-Encrypted-User: User input encrypted using encryption key
* **Body**:
  * **N/A**

### Response Spec

* \[] -> List of Lambda objects

### Request Example

```http
POST / HTTP/1.1
Host: tiramisu.0xpass.io
Content-Type: application/json
X-Session: eJjdnfdknf...
X-Encrypted-Key: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcKMTO8R/F0wbonGZM0NZBg2X94FvirH6Hi2U1zFlXN5srkOdvQL3lVNZ86gbfEtJFPOEAeZkxtTOKOsH4ZXPtUbFOjT2Niblo8njOKibOoAMRKIhtsNTTvRXjHRxnNqVs3QcSe7XbO1DbH/pdRgq+YZN13znlSRsupu4G/h/KBEZr98wXFo8PeDV9F8ZV56F90GqQ3wKzFUBwC9rJihGz0omH+eJA0jB/K7BYt30fhWDnqaLNP2eb1mbIjBCmv6sXqu2jtghr3ejl0YwjP9lCO+aVD7bophfb/IyKg==
X-Encrypted-User: jp6t2GVOvzltN+4VGc21ZKPIbLjEvitE34cFYDvVNrcmF2ukcK
{
    "jsonrpc": "2.0",
    "method": "listLambda",
    "params": {},
    "id": 3
}
```

### Response Example

Success:

```json
{
    "jsonrpc": "2.0",
    "result": [
        {
            "id": "153634-f572-40ee-ba2a-efee345a3691",
            "config": {
                "actions": {
                    "data": "0x000000",
                    "substitution": true,
                    "type": "personal_sign"
                },
                "authorization": {
                    "type": "none"
                },
                "triggers": [
                   { "type": "hook"},
                ],
                "conditions": [
                    {
                        "code": "return true",
                        "output_type": "integer",
                        "substitution": true,
                        "type": "code"
                    }
                ],
                "envs": [],
                "max_executions": 0,
                "postHook": [],
                "verifications": {
                    "count": 1
                }
            },
            "status": "ready",
            "proof": null,
            "created_at": "2024-03-29T19:28:43",
            "updated_at": "2024-03-29T19:46:48",
            "total_executions": 2,
            "ok_executions": 2
        }
    ]
}
```

Error:

```json
{
  "jsonrpc": "2.0",
  "error": {
    "code": 401,
    "message": "Unauthorized: Signature verification failed."
  },
  "id": 1
}
```


# Moving to Mainnet

The default configuration of our SDK, as well as the API endpoint examples are both setup to get developers running in a testnet environment, once you are comfortable with your setup, and would like to move to production, there are some very minor changes to make to SDK configurations.

If using the API endpoints directly, to access a Mainnet Passport Node, you can simply use `https://mochi.0xpass.io` .

For SDK configuration you can instantiate your Passport instance as follows simply passing `Network.MAINNET` as your chosen network.

```javascript
import { Passport, Network } from "@0xpass/passport"
import { WebAuthnSigner } from "@0xpass/webauthn-signer"

const signer = new WebauthnSigner({
      rpId: window.location.hostname,
      rpName: "rpName",
});

const passport  = new Passport({
      scopeId: scopeId,
      signer: signer
      network: Network.MAINNET,
});
```

When using the viem client you equally instantiate it choosing the Mainnet network as follows.

```javascript
import { http, mainnet, WalletClient } from "viem/chains";
import { createPassportClient } from "@0xpass/passport-viem";
import { Passport, Network } from "@0xpass/passport";

const signer: new WebauthnSigner({
  rpId: "rpId",
  rpName: "rpName",
})

const passport = new Passport({
    scopeId: "insert_your_scope_id",
    signer: signer
});

const userInput {
   username: "insert_registered_username_here"
   userDisplayName: "insert_registered_user_display_name_here"
}

await passport.setupEncryption();
const [authenticatedHeader] = await passport.authenticate(userInput);

const chain = mainnet;
const transport = http("any eth node endpoint");

// Create viem WalletClient using Passport
const client: WalletClient = await createPassportClient(
  authenticatedHeader,
  transport,
  chain,
  Network.MAINNET // define mainnet network here
);
```


# State Of The Network

### Access Endpoints

Below are the endpoints for accessing different passport network environments:

* **Testnet Endpoint:** `tiramisu.0xpass.io`
* **Mainnet Endpoint:** `TBD`

It is important to note that entities and authorisation credentials cannot be interchanged or used across these environments. This segregation ensures the integrity and isolation of testing and production environments.


# Generating DOA Keys

In order to use DOA, you need to pass the base64 encoded private key. Here is how you generate your private key:

## Generate the PEM Key

### Using Passport SDK

Install `passport-scope-cli`

{% tabs %}
{% tab title="npm" %}

<pre class="language-bash"><code class="lang-bash"><strong>npm install -g passport-scope-cli
</strong></code></pre>

{% endtab %}

{% tab title="yarn" %}

```bash
yarn global add passport-scope-cli
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm install -g passport-scope-cli
```

{% endtab %}
{% endtabs %}

Run the generate key command

```bash
passport-scope generate-keys --name passport
```

Post this, your private key file will be created in the same directory with name passport\_priv.der

### Using OpenSSL

```sh
openssl ecparam -name prime256v1 -genkey -noout -out private_key.pem
openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out passport_priv.der -nocrypt
```

## Base64 encode the Key

```shell
base64 -i passport_priv.der -o pasport_priv_base64.txt
```

And you are done, you may copy this value directly to your environment variable


# API Request Setup

To interact with the Passport Protocol API, there are two types of requests "Unauthenticated" which don't require an authenticated user account,  and "Authenticated" which do require an authenitcated user account. The following provides information on how the request headers for each request type works and the reasoning behind them, but you can skip to [Unauthenticated Requests](/appendix/api-request-setup/unauthenticated-requests) or [Authenticated Requests](/appendix/api-request-setup/authenticated-requests) to see how these headers are setup.

## Unauthenticated Requests

RPC request methods such as

* initiateRegistration
* completeRegistration
* initiateAuthentication
* completeAuthentication
* delegateRegistration
* executeLambda (\* depends on the lambda authorization type)

These request methods are "unauthenticated", and require you to use the 2 following request headers `x-scope-id` and `x-encrypted-key`

### Scope

| Header       | Description                                                                                                                                                                                        |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-Scope-Id` | Identifies the application's scope under which the user's account is being registered or authenticated. It contextualizes the request to a specific domain, enabling correct policy and procedure. |

### **End to End Encryption**

<table><thead><tr><th width="325">Header</th><th>Description</th></tr></thead><tbody><tr><td>X<code>-Encrypted-Key</code></td><td>Carries an encrypted version of AES key for the server to securely process the request, especially for operations requiring encryption or decryption of user data.<br>AES Key is random and generated locally on your device. This key is then encrypted by using Public Enclave RSA Key. You can find this key in any of the SDK examples.</td></tr></tbody></table>

### **User Identifier**

<table><thead><tr><th width="325">Header</th><th>Description</th></tr></thead><tbody><tr><td>X<code>-Encrypted-User</code></td><td><p>Carries an encrypted version of user details for the server to securely process the request. This is encrypted using the aes key which is generated above. Here is a sample user details<br></p><pre class="language-json"><code class="lang-json">{
    username: "john_doe",
    userDisplayName: "john_doe_crypto",
}

</code></pre></td></tr></tbody></table>

## Authenticated Requests

Authentication headers are essential for maintaining session integrity, authenticating user actions, and ensuring secure interactions. These apply to the following endpoints:

* eth\_signTransaction
* personal\_sign
* createLambda
* listLambda
* executeLambda (\* depends on the lambda authorization type)

### **Authentication**

Any authenticated request must containone of the following 3 headers:

<table><thead><tr><th>Header</th><th>Description</th></tr></thead><tbody><tr><td><code>X-Encrypted-Session</code></td><td>This is obtained when you authenticate with the <a data-mention href="/pages/AEfM9ykoAYQpIdz4Tt1B">/pages/AEfM9ykoAYQpIdz4Tt1B</a> endpoint. This is used by enclave to verify  your requests.</td></tr><tr><td><code>X-Encrypted-WebAuthn-Signature</code></td><td><p>This is obtained by directly singing the user object using your passkeys</p><pre><code> {
    username: "john_doe",
    userDisplayName: "john_doe_crypto",
 }
</code></pre></td></tr><tr><td><code>X-Encrypted-Key-Signature</code></td><td><p></p><p>This is obtained by directly singing the user object using your DOA key.</p><pre><code> {
    username: "john_doe",
    userDisplayName: "john_doe_crypto",
 }
</code></pre></td></tr></tbody></table>

### **End to End Encryption**

<table><thead><tr><th width="321">Header</th><th>Description</th></tr></thead><tbody><tr><td><code>X-Encrypted-Key</code></td><td>Carries an encrypted version of AES key for the server to securely process the request, especially for operations requiring encryption or decryption of user data.<br>AES Key is random and generated locally on your device. This key is then encrypted by using Public Enclave RSA Key. You can find this key in any of the SDK examples.</td></tr></tbody></table>

### **User Identifier**

<table><thead><tr><th width="325">Header</th><th>Description</th></tr></thead><tbody><tr><td>X<code>-Encrypted-User</code></td><td><p>Carries an encrypted version of user details for the server to securely process the request. This is encrypted using the aes key which is generated above. Here is a sample user details<br></p><pre class="language-json"><code class="lang-json">{
    username: "john_doe",
    userDisplayName: "john_doe_crypto",
}

</code></pre></td></tr></tbody></table>

### Scope

| Header       | Description                                                                                                                                                                                        |
| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `X-Scope-Id` | Identifies the application's scope under which the user's account is being registered or authenticated. It contextualizes the request to a specific domain, enabling correct policy and procedure. |


# Unauthenticated Requests

To carry out an unauthenticated request, 3 headers are required, `X-Scope-Id` and `X-Encrypted-Key` and `X-Encrypted-User` .&#x20;

`X-Scope-Id` is the ID of the application's scope under which the user's account is being registered or authenticated. You can read more about [Configuring your scope](/authentication/configuring-your-scope). Once you've set up your scope and have the ID you can simply past it in the request header here.&#x20;

To setup an `X-Encrypted-Key` you need to generate a random AES Key, and then RSA encrypt it with the secure enclaves public key, we'll use TypeScript for the example below.

Here we setup a `cryptoObj` that can work in both browser and server environments and then a function to generate an AES Key.

```javascript
const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;

export const generateAesKey = async () => {
  const cryptoKey = await cryptoObj.subtle.generateKey(
    {
      name: "AES-GCM",
      length: 256,
    },
    true,
    ["encrypt", "decrypt"]
  );
  return await cryptoObj.subtle.exportKey("raw", cryptoKey);
};
```

Next we setup two function an `encrypt` function, which we then use in our `rsaEncrypt` function.

```typescript
const encrypt = async (algo, key, data) => {
  try {
    const encryptedResult = await cryptoObj.subtle.encrypt(algo, key, data);
    return encryptedResult;
  } catch (error) {
    console.error("Encryption error:", error);
    throw error;
  }
};

const rsaEncrypt = async (
  plainText: string,
  encryptionKey: BufferSource,
  keyFormat: "spki" = "spki",
  hashName: "SHA-256" = "SHA-256"
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }

  const encoder = new TextEncoder();
  const data = encoder.encode(plainText);

  let cryptoKey: CryptoKey;
  let encrypted: ArrayBuffer;

  try {
    cryptoKey = await importKey(
      keyFormat,
      encryptionKey,
      { name: "RSA-OAEP", hash: { name: hashName } },
      ["encrypt"]
    );
    encrypted = await encrypt({ name: "RSA-OAEP" }, cryptoKey, data);
    return btoa(String.fromCharCode.apply(null, new Uint8Array(encrypted)));
  } catch (error) {
    console.error("RSA-OAEP Encryption error:", error);
    throw error;
  }
};


export const aesEncrypt = async (
  plainText: string,
  encryptionKey: BufferSource,
  keyFormat: "raw" = "raw",
  keyLength: number = 256
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }

  const encoder = new TextEncoder();
  const data = encoder.encode(plainText);
  let cryptoKey: CryptoKey;
  let encrypted: ArrayBuffer;

  try {
    cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
      "encrypt",
    ]);

    const iv = cryptoObj.getRandomValues(new Uint8Array(12)); // Initialization vector

    encrypted = await encrypt({ name: "AES-GCM", iv }, cryptoKey, data);

    const combined = new Uint8Array(iv.length + encrypted.byteLength);
    combined.set(iv, 0);
    combined.set(new Uint8Array(encrypted), iv.length);

    return btoa(String.fromCharCode.apply(null, combined));
  } catch (error) {
    console.error("AES-GCM Encryption error:", error);
    throw error;
  }
};

```

&#x20;With these function setup, we are able to generate our AES key, and then RSA Encrypt it using the public key of the secure enclave.&#x20;

```typescript
const enclavePublicKey = 
  "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvQOa1gkatuN6KjaS4KEWsVZAN9i4Cf0j9jlmBW5RwCJ3Bxo32McP7axt4Ev6sMWM24lpCgXgu68S9KBYRcrcEB6dRcaupFGd+ER7M518fiJ0VtCZ+XRnmwn9fqEvotp9DPZOysJkUQ60kugCRKwNvfZzAFcDiubwiqsUY2sCm943a/u9Hym51SEetG+ZFPJZFOBqwRSGkOgGZ+9Ac7ITE+bWLCZk9DlzRu+BIoDOFzXZIn+/0a0X8BnLtRY4g50aew4J+4OllQagBbhYnPMvYExYIEUx6bdjQicw0Js6s2pHr+SFAX23kQtbVOVxb5+KEGp1d+6Q4Gx7FBoyWI5qPQIDAQAB";

const aesKey = await generateAesKey();
const aesKeyBytes = new Uint8Array(aesKey);
const aesKeyString = btoa(String.fromCharCode(...aesKeyBytes));
const encryptedAesKey = await rsaEncrypt(aesKeyString, enclavePublicKey);
const userDetails = {
    username: "john_doe",
    userDisplayName: "john_doe_crypto",
};
const encryptedUser = await aesEncrypt(JSON.stringify(userDetails), aesKey);
```

Now you have your `encryptedAesKey` and `encryptedUser` you can use this value as the value in the request header as `X-Encrypted-Key` . With `X-Scope-Id, X-Encrypted-User` and `X-Encrypted-Key` setup, you can now start interacting with Passport API to register and authenticate users.


# Authenticated Requests

To carry out an unauthenticated request, 4 headers are required:

1. Authentication Header - `X-Encrypted-Session or`` ``X-Encrypted-WebAuthn-Signature or`` ``X-Encrypted-Key-Signature`
2. `X-Encrypted-Key`
3. `X-Encrypted-User`&#x20;
4. `X-Scope-Id`&#x20;

`X-Encrypted-Session` is obtained when you authenticate with the [Authenticating with API](/authentication/passkeys/authentication/authenticating-with-api) endpoint. This is used by enclave to verify  your requests. Other 2 types of headers are obtained by signing the user details object directly using your auth method (passkeys or private key)

To setup an `X-Encrypted-Key` you need to generate a random AES Key, and then RSA encrypt it with the secure enclaves public key, we'll use TypeScript for the example below.

Here we setup a `cryptoObj` that can work in both browser and server environments and then a function to generate an AES Key.

```javascript
const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;

export const generateAesKey = async () => {
  const cryptoKey = await cryptoObj.subtle.generateKey(
    {
      name: "AES-GCM",
      length: 256,
    },
    true,
    ["encrypt", "decrypt"]
  );
  return await cryptoObj.subtle.exportKey("raw", cryptoKey);
};
```

Next we setup two function an `encrypt` function, which we then use in our `rsaEncrypt` function.

```typescript
const encrypt = async (algo, key, data) => {
  try {
    const encryptedResult = await cryptoObj.subtle.encrypt(algo, key, data);
    return encryptedResult;
  } catch (error) {
    console.error("Encryption error:", error);
    throw error;
  }
};

const rsaEncrypt = async (
  plainText: string,
  encryptionKey: BufferSource,
  keyFormat: "spki" = "spki",
  hashName: "SHA-256" = "SHA-256"
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }

  const encoder = new TextEncoder();
  const data = encoder.encode(plainText);

  let cryptoKey: CryptoKey;
  let encrypted: ArrayBuffer;

  try {
    cryptoKey = await importKey(
      keyFormat,
      encryptionKey,
      { name: "RSA-OAEP", hash: { name: hashName } },
      ["encrypt"]
    );
    encrypted = await encrypt({ name: "RSA-OAEP" }, cryptoKey, data);
    return btoa(String.fromCharCode.apply(null, new Uint8Array(encrypted)));
  } catch (error) {
    console.error("RSA-OAEP Encryption error:", error);
    throw error;
  }
};


export const aesEncrypt = async (
  plainText: string,
  encryptionKey: BufferSource,
  keyFormat: "raw" = "raw",
  keyLength: number = 256
) => {
  if (!encryptionKey) {
    throw Error("Encryption key not initialized");
  }

  const encoder = new TextEncoder();
  const data = encoder.encode(plainText);
  let cryptoKey: CryptoKey;
  let encrypted: ArrayBuffer;

  try {
    cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
      "encrypt",
    ]);

    const iv = cryptoObj.getRandomValues(new Uint8Array(12)); // Initialization vector

    encrypted = await encrypt({ name: "AES-GCM", iv }, cryptoKey, data);

    const combined = new Uint8Array(iv.length + encrypted.byteLength);
    combined.set(iv, 0);
    combined.set(new Uint8Array(encrypted), iv.length);

    return btoa(String.fromCharCode.apply(null, combined));
  } catch (error) {
    console.error("AES-GCM Encryption error:", error);
    throw error;
  }
};

```

&#x20;With these function setup, we are able to generate our AES key, and then RSA Encrypt it using the public key of the secure enclave.&#x20;

```typescript
const enclavePublicKey = 
  "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvQOa1gkatuN6KjaS4KEWsVZAN9i4Cf0j9jlmBW5RwCJ3Bxo32McP7axt4Ev6sMWM24lpCgXgu68S9KBYRcrcEB6dRcaupFGd+ER7M518fiJ0VtCZ+XRnmwn9fqEvotp9DPZOysJkUQ60kugCRKwNvfZzAFcDiubwiqsUY2sCm943a/u9Hym51SEetG+ZFPJZFOBqwRSGkOgGZ+9Ac7ITE+bWLCZk9DlzRu+BIoDOFzXZIn+/0a0X8BnLtRY4g50aew4J+4OllQagBbhYnPMvYExYIEUx6bdjQicw0Js6s2pHr+SFAX23kQtbVOVxb5+KEGp1d+6Q4Gx7FBoyWI5qPQIDAQAB";

const aesKey = await generateAesKey();
const aesKeyBytes = new Uint8Array(aesKey);
const aesKeyString = btoa(String.fromCharCode(...aesKeyBytes));
const encryptedAesKey = await rsaEncrypt(aesKeyString, enclavePublicKey);
const userDetails = {
    username: "john_doe",
    userDisplayName: "john_doe_crypto",
};
const encryptedUser = await aesEncrypt(JSON.stringify(userDetails), aesKey);
```

Now you have your `encryptedAesKey` and `encryptedUser` you can use this value as the value in the request header as `X-Encrypted-Key` . With `X-Scope-Id, X-Encrypted-User` , X-Encrypted-Session and `X-Encrypted-Key` setup, you can now start interacting with Passport API to sign messages, transactions and everythig else!


