Skip to content

Commit 8ee4bc5

Browse files
authored
Merge pull request #246 from Nityam573/develop
login using privado docs
2 parents 7bafe7c + f50702e commit 8ee4bc5

File tree

2 files changed

+262
-0
lines changed

2 files changed

+262
-0
lines changed

docs/wallet/login-with-privado.md

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
---
2+
id: login-with-privado
3+
title: Login Using Privado ID Guide
4+
sidebar_label: Login Using Privado ID
5+
description: Tutorial on how to use Privado ID for login.
6+
keywords:
7+
- docs
8+
- privado id
9+
- login
10+
- issuer
11+
- verifier
12+
- authentication
13+
---
14+
15+
import Tabs from '@theme/Tabs';
16+
import TabItem from '@theme/TabItem';
17+
import useBaseUrl from '@docusaurus/useBaseUrl';
18+
19+
A hands-on developer guide to integrate Login with Privado ID — a simple, decentralized authentication method using Decentralised Identifiers (DIDs), without any zero-knowledge proofs required.
20+
21+
## Overview
22+
23+
Implement **Login with Privado ID** to add a secure, decentralized authentication experience to your application — similar to “Login with Google,” but powered by Decentralized Identifiers (DIDs).
24+
25+
This guide walks you through setting up **basic authentication** using Privado ID. It verifies user identity through DID ownership
26+
27+
### Key Capabilities
28+
- **Authenticates DID Ownership**: Authenticates users by cryptographically proving ownership of their DID
29+
30+
- **Enables Trustless Authentication**: Removes reliance on centralized identity providers.
31+
32+
- **Delivers a Familiar Web2 Experience**
33+
34+
## How Basic Authentication Works
35+
36+
The Login with Privado ID flow authenticates users by verifying control over their DID.
37+
Below is a high-level breakdown of how the flow works end-to-end:
38+
39+
1. The user clicks “Login with Privado ID” on the app, which triggers a request to the backend(`/api/sign-in` endpoint) to generate a new authentication request for the user
40+
41+
:::info
42+
43+
You may also display a QR code that users can scan with the Privado ID Wallet app to start the same flow
44+
45+
:::
46+
47+
2. The frontend takes the authentication request from the backend, encodes it in Base64, and configures it into a [Universal Link](./universal-links.md). This link opens the Privado ID Web Wallet, prompting the user to sign-in with their crypto wallet
48+
49+
3. Once sign-in with crypto wallet is approved by user, the Privado wallet generates a `signed JWZ` (JSON Web Zero-knowledge) token — a verifiable proof of DID ownership.
50+
51+
4. The wallet then automatically sends a POST request to the backend’s `/api/callback` endpoint containing the `sessionId` and the `signed JWZ` token for verification
52+
53+
5. The backend verifies the signed JWZ token against the stored authentication request using the Privado Verifier
54+
55+
6. Once the JWZ is validated, you can consider the user’s DID as verified and proceed to create or update their record in your database.
56+
57+
7. From here, your application can decide what to do with this verified DID — such as enabling login, granting access, or allowing participation in specific flows like airdrops or allowlists
58+
59+
## Setup
60+
61+
```bash
62+
npm install @iden3/js-iden3-auth express cors raw-body
63+
```
64+
65+
To get started with Login with Privado ID, ensure the following environment requirements are met:
66+
67+
- **Keys Directory**: Contains circuit and verification key files for validation. A sample structure is available in the [verifier-integration](https://github.com/0xPolygonID/tutorial-examples/tree/main/verifier-integration) repository under the `keys/` folder
68+
- **Public URL**: For receiving authentication callbacks (use ngrok for development)
69+
70+
### 1. Server Configuration
71+
Sets up Express server with required middleware and routes for handling authentication requests and callbacks.
72+
73+
```javascript
74+
// index.js
75+
const path = require("path");
76+
const express = require("express");
77+
const { auth, resolver } = require("@iden3/js-iden3-auth");
78+
const getRawBody = require("raw-body");
79+
const cors = require('cors');
80+
81+
const app = express();
82+
const port = 8080;
83+
84+
app.use(express.static("./static"));
85+
app.use(cors());
86+
87+
// Session storage for auth requests
88+
const requestMap = new Map();
89+
90+
// Routes
91+
app.get("/api/sign-in", getAuthRequest);
92+
app.post("/api/callback", callback);
93+
94+
app.listen(port, () => {
95+
console.log(`Server running on port ${port}`);
96+
});
97+
```
98+
99+
:::info
100+
101+
**Testing Frontend**: The `./static` directory includes a simple frontend to test the full authentication flow — QR code generation, Universal Link handling, and callback processing.
102+
Once the flow works locally, integrate the same endpoints into your production frontend, update the callback to your live URL, and secure configurations with environment variables and HTTPS.
103+
104+
:::
105+
106+
### 2. Authentication Request Handler
107+
Generates basic authentication requests with empty scope and stores them with unique session IDs for later verification.
108+
109+
```javascript
110+
async function getAuthRequest(req, res) {
111+
try {
112+
// Configuration - Update these for your setup
113+
const hostUrl = " Your public URL";
114+
const callbackURL = "/api/callback";
115+
const audience = "did:polygonid:polygon:amoy:2qQ68JkRcf3xrHPQPWZei3YeVzHPP58wYNxx2mEouR"; // Your verifier DID
116+
117+
// Generate unique session
118+
const sessionId = Date.now();
119+
const uri = `${hostUrl}${callbackURL}?sessionId=${sessionId}`;
120+
121+
// Create basic auth request (no proofs required)
122+
const request = auth.createAuthorizationRequest(
123+
"Basic Sign In", // Reason for authentication
124+
audience, // Your verifier DID
125+
uri // Callback URL
126+
);
127+
128+
request.body.scope = [];
129+
130+
// Store for later verification
131+
requestMap.set(`${sessionId}`, request);
132+
133+
console.log(`Created basic auth request for session: ${sessionId}`);
134+
return res.status(200).json(request);
135+
136+
} catch (error) {
137+
console.error("Error creating auth request:", error);
138+
return res.status(500).json({ error: "Failed to create auth request" });
139+
}
140+
}
141+
```
142+
143+
:::info
144+
145+
**Getting Your Verifier DID**: Sign in to your [Privado ID Wallet](https://wallet.privado.id/) and use the DID displayed there as your verifier DID for simplicity during development.
146+
147+
:::
148+
149+
## How Does `getAuthRequest` Connect to Privado ID Wallet?
150+
151+
This is where [**Universal Links**](./universal-links.md) come into play! Your frontend takes the auth request returned by `getAuthRequest()`, encodes it in Base64, and embeds it into a Universal Link which in turn redirects the user to Privado ID wallet. The wallet processes the request, prompts the user to sign, and then posts a signed JWZ (JSON Web Zero-knowledge) token to your callback endpoint. That JWZ is what your backend verifies to confirm DID ownership, and thus delivers a seamless login flow across web and mobile.
152+
153+
### Universal Link Structure
154+
155+
```javascript
156+
https://wallet.privado.id/#i_m=<base64_encoded_auth_request>
157+
```
158+
159+
**Components:**
160+
- **Base URL**: `https://wallet.privado.id/` - Privado ID wallet endpoint
161+
- **Fragment**: `#i_m=` - Parameter for auth request
162+
163+
### 3. Verification Callback Handler
164+
Receives JWZ token as a callback, validates them against stored authentication requests, and confirms user DID ownership.
165+
166+
```javascript
167+
async function callback(req, res) {
168+
try {
169+
// 1. Extract session and token
170+
const sessionId = req.query.sessionId;
171+
if (!sessionId) {
172+
return res.status(400).json({ error: "Session ID is required" });
173+
}
174+
175+
const raw = await getRawBody(req);
176+
const tokenStr = raw.toString().trim();
177+
if (!tokenStr) {
178+
return res.status(400).json({ error: "Token is required" });
179+
}
180+
181+
// 2. Setup blockchain resolvers
182+
const resolvers = {
183+
["polygon:amoy"]: new resolver.EthStateResolver(
184+
"<POLYGON_AMOY_RPC_URL>",
185+
"0x1a4cC30f2aA0377b0c3bc9848766D90cb4404124"
186+
),
187+
["privado:main"]: new resolver.EthStateResolver(
188+
"https://rpc-mainnet.privado.id",
189+
"0x3C9acB2205Aa72A05F6D77d708b5Cf85FCa3a896"
190+
)
191+
};
192+
193+
// 3. Retrieve stored auth request
194+
const authRequest = requestMap.get(`${sessionId}`);
195+
if (!authRequest) {
196+
return res.status(400).json({
197+
error: "Invalid session ID or session expired"
198+
});
199+
}
200+
201+
// 4. Initialize verifier
202+
const keyDIR = "./keys";
203+
const verifier = await auth.Verifier.newVerifier({
204+
stateResolver: resolvers,
205+
circuitsDir: path.join(__dirname, keyDIR),
206+
ipfsGatewayURL: "https://ipfs.io",
207+
});
208+
209+
// 5. Verify authentication
210+
const opts = {
211+
AcceptedStateTransitionDelay: 5 * 60 * 1000, // 5 minutes
212+
};
213+
214+
const authResponse = await verifier.fullVerify(tokenStr, authRequest, opts);
215+
216+
// 6. Clean up and respond
217+
requestMap.delete(`${sessionId}`);
218+
219+
console.log(`Authentication successful for session: ${sessionId}`);
220+
console.log("User DID:", authResponse.from);
221+
222+
return res.status(200).set("Content-Type", "application/json").send(authResponse);
223+
224+
} catch (error) {
225+
console.error("Authentication error:", error);
226+
return res.status(500).json({
227+
error: "Authentication failed",
228+
details: error.message
229+
});
230+
}
231+
}
232+
```
233+
234+
You’ve successfully verified DID ownership.
235+
236+
To turn this into a complete login, store user session details by their DID in your database. The DID acts as a persistent identity, allowing your app to recognize returning users.
237+
238+
When a user logs in again with the same Privado ID Wallet, they’ll present the same DID, letting your application instantly identify them and deliver the right personalized experience — decentralized, secure, and private.
239+
240+
### Testing Steps
241+
242+
1. **Visit your app:** `http://localhost:8080`
243+
2. **Test universal link:** Click "Login" button
244+
245+
You can test the full authentication loop — from generating the auth request to verifying the DID — ensuring your app correctly recognizes verified users
246+
247+
---
248+
249+
## Going Further: Beyond Basic Login
250+
251+
With **Login with Privado ID**, you’re not just authenticating users — you’re building the foundation for a unified Web3 identity layer.
252+
Once DID-based login is in place, it can power any authentication experience — from crypto wallet sign-ins to Privado credentials, or even Google 2FA — all anchored to a single decentralized identity.
253+
254+
## Resources
255+
256+
### Example Repository
257+
- [Repo](https://github.com/0xPolygonID/tutorial-examples/tree/main/verifier-integration/login-privado)
258+
259+
---
260+
261+
This implementation provides a solid foundation for Privado ID basic authentication. For advanced use cases involving credential verification and zero-knowledge proofs, refer to the [query-based authentication](../verifier/verification-library/verifier-set-up.md) example.

sidebars.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ module.exports = {
185185

186186
]
187187
},
188+
"wallet/login-with-privado",
188189
{
189190
type: "category",
190191
label: "Wallet SDK",

0 commit comments

Comments
 (0)