Skip to content

Commit ee90ddb

Browse files
committed
feat: implement BLUM authentication flow with admin and user tiers
1 parent c876267 commit ee90ddb

2 files changed

Lines changed: 407 additions & 0 deletions

File tree

Lines changed: 303 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
# BLUM Authentication Integration Guide
2+
3+
## Overview
4+
5+
This guide provides a comprehensive explanation of the BLUM authentication integration with the ArchAI platform. The BLUM integration enables Telegram-based user authentication through a secure, wallet-backed system that combines traditional Web3 authentication with Telegram identity verification.
6+
7+
## Architecture
8+
9+
The BLUM authentication system implements a **two-tier authentication architecture**:
10+
11+
1. **Admin Tier**: A privileged account with administrative rights that can authorize user registrations
12+
2. **User Tier**: End users authenticated through Telegram IDs and wallet signatures
13+
14+
```
15+
┌─────────────────────────────────────────────────────────┐
16+
│ BLUM Auth Flow │
17+
│ │
18+
│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │
19+
│ │ Admin │─────►│ BadAI │◄─────│ BLUM User │ │
20+
│ │ Wallet │ │ Platform │ │ + Telegram │ │
21+
│ └──────────┘ └──────────┘ └──────────────┘ │
22+
│ │ │ │ │
23+
│ │ 1. Admin Auth │ │ │
24+
│ │─────────────────►│ │ │
25+
│ │ │ │ │
26+
│ │ 2. Admin Session │ │ │
27+
│ │◄─────────────────│ │ │
28+
│ │ │ │ │
29+
│ │ │ 3. User Challenge │ │
30+
│ │ │◄───────────────────│ │
31+
│ │ │ │ │
32+
│ │ 4. User Auth │ │ │
33+
│ │ (via admin │ │ │
34+
│ │ session) │ │ │
35+
│ │─────────────────►│ │ │
36+
│ │ │ │ │
37+
│ │ │ 5. User Session │ │
38+
│ │ │───────────────────►│ │
39+
│ │
40+
└─────────────────────────────────────────────────────────┘
41+
```
42+
43+
## Why Two-Tier Authentication?
44+
45+
The two-tier architecture provides several critical benefits:
46+
47+
1. **Access Control**: Admin accounts can gate user registration and authentication
48+
2. **Telegram Integration**: Binds wallet addresses to Telegram user IDs for social verification
49+
3. **Audit Trail**: All user authentications are traceable through admin sessions
50+
4. **Partner Integration**: Allows BLUM to maintain control over user onboarding
51+
52+
## Prerequisites
53+
54+
Before implementing BLUM authentication, ensure you have:
55+
56+
- `@badaitech/badai-api` package installed
57+
- `viem` for wallet operations
58+
- Admin wallet private key (with appropriate permissions)
59+
- Access to user Telegram IDs
60+
61+
### Installation
62+
63+
### Important: NPM Registry Configuration
64+
65+
The `@badaitech` packages are hosted on GitHub Package Registry. You need to configure npm to use the correct registry for `@badaitech` scoped packages.
66+
67+
Create or update your `.npmrc` file in your project root:
68+
69+
```bash
70+
@badaitech:registry=https://npm.pkg.github.com
71+
```
72+
73+
Or configure globally:
74+
75+
```bash
76+
npm config set @badaitech:registry https://npm.pkg.github.com
77+
```
78+
79+
### Install Dependencies
80+
81+
```bash
82+
npm install @badaitech/badai-api viem
83+
```
84+
85+
## Authentication Flow
86+
87+
### Step 1: Admin Authentication
88+
89+
The admin must authenticate first to obtain a privileged session token.
90+
91+
```typescript
92+
import { createGraphQLClient, GraphQL } from '@badaitech/badai-api'
93+
import { privateKeyToAccount } from 'viem/accounts'
94+
95+
const restClient = createGraphQLClient('https://api.badai.io/graphql')
96+
97+
// Load admin credentials
98+
const adminPrivateKey = process.env.ADMIN_PRIVATE_KEY
99+
const account = privateKeyToAccount(adminPrivateKey as `0x${string}`)
100+
101+
// 1. Request authentication challenge
102+
const { authMetamaskMessage } = await restClient.request(
103+
GraphQL.AuthMetamaskMessageDocument,
104+
{ address: account.address }
105+
)
106+
107+
// 2. Sign the challenge message
108+
const signature = await account.signMessage({
109+
message: authMetamaskMessage
110+
})
111+
112+
// 3. Exchange signature for admin session
113+
const { authMetamaskLogin } = await restClient.request(
114+
GraphQL.AuthMetamaskLoginDocument,
115+
{
116+
input: {
117+
authMessage: authMetamaskMessage,
118+
sign: signature,
119+
}
120+
}
121+
)
122+
123+
const adminSession = authMetamaskLogin.session
124+
console.log('Admin authenticated:', account.address)
125+
```
126+
127+
**Security Note**: The admin private key should be stored securely and never exposed to end users. Use environment variables or secure key management systems.
128+
129+
### Step 2: User Authentication with Telegram
130+
131+
Once the admin session is established, you can authenticate BLUM users with their Telegram IDs and wallet signatures.
132+
133+
```typescript
134+
import { generatePrivateKey } from 'viem/accounts'
135+
136+
// Generate or retrieve user wallet
137+
const userPrivateKey = generatePrivateKey() // Or load existing key
138+
const userAccount = privateKeyToAccount(userPrivateKey)
139+
const telegramID = 123456789 // User's Telegram ID from BLUM
140+
141+
// 1. Request BLUM-specific authentication challenge
142+
const { authBlumMetamaskMessage } = await restClient.request(
143+
GraphQL.AuthBlumMetamaskMessageDocument,
144+
{
145+
address: userAccount.address,
146+
input: {
147+
telegramID: telegramID,
148+
sign: 'field_for_future_sign', // Reserved for future BLUM signature
149+
}
150+
}
151+
)
152+
153+
// 2. User signs the challenge with their wallet
154+
const userSignature = await userAccount.signMessage({
155+
message: authBlumMetamaskMessage
156+
})
157+
158+
// 3. Complete authentication using admin session
159+
const { authBlumMetamaskLogin } = await restClient.request(
160+
GraphQL.AuthBlumMetamaskLoginDocument,
161+
{
162+
session: adminSession, // ⚠️ Requires admin session
163+
input: {
164+
authMessage: authBlumMetamaskMessage,
165+
sign: userSignature,
166+
}
167+
}
168+
)
169+
170+
const userSession = authBlumMetamaskLogin.session
171+
const userProfile = authBlumMetamaskLogin.user_profile
172+
173+
console.log('User authenticated:', userAccount.address)
174+
console.log('Telegram ID:', telegramID)
175+
console.log('Session:', userSession)
176+
```
177+
178+
### Step 3: Using the User Session
179+
180+
Once authenticated, the user session can be used for all API operations:
181+
182+
```typescript
183+
// Fetch user profile
184+
const { userProfile } = await restClient.request(
185+
GraphQL.GetUserProfileDocument,
186+
{ session: userSession }
187+
)
188+
189+
// Create chat rooms
190+
const { createChatRoom } = await restClient.request(
191+
GraphQL.CreateChatRoomDocument,
192+
{
193+
session: userSession,
194+
agents: ['agent-id-here'],
195+
}
196+
)
197+
198+
// Send messages, interact with agents, etc.
199+
```
200+
201+
## Complete Implementation Example
202+
203+
See the full working example in `src/blum-login.ts`:
204+
205+
```typescript
206+
import process from 'node:process'
207+
import { createGraphQLClient, GraphQL } from '@badaitech/badai-api'
208+
import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts'
209+
210+
const restApiUrl = process.env.REST_API_URL ?? 'http://localhost:9151/graphql'
211+
const adminPrivateKey = process.env.ADMIN_PRIVATE_KEY ?? ''
212+
213+
async function main() {
214+
if (!adminPrivateKey) {
215+
console.error('Please set the ADMIN_PRIVATE_KEY environment variable.')
216+
process.exit(1)
217+
}
218+
219+
// Initialize clients
220+
const restClient = createGraphQLClient(restApiUrl)
221+
222+
// 1. Admin flow
223+
// Generate wallet credentials
224+
// const privateKey = generatePrivateKey()
225+
const account = privateKeyToAccount(adminPrivateKey as `0x${string}`)
226+
console.log('Admin address:', account.address)
227+
228+
// Authenticate admin
229+
const { authMetamaskMessage } = await restClient.request(
230+
GraphQL.AuthMetamaskMessageDocument,
231+
{ address: account.address },
232+
)
233+
234+
const signature = await account.signMessage({ message: authMetamaskMessage })
235+
236+
const { authMetamaskLogin } = await restClient.request(
237+
GraphQL.AuthMetamaskLoginDocument,
238+
{
239+
input: {
240+
authMessage: authMetamaskMessage,
241+
sign: signature,
242+
},
243+
},
244+
)
245+
246+
const adminSession = authMetamaskLogin.session
247+
248+
// 2. User flow
249+
// Generate wallet credentials
250+
const userPrivateKey = generatePrivateKey()
251+
console.log('User private key (save this!):', userPrivateKey)
252+
const userAccount = privateKeyToAccount(userPrivateKey)
253+
const userTelegramID = Math.floor(Math.random() * 1000000) // TODO: Set real Telegram ID here
254+
console.log('User address:', userAccount.address)
255+
256+
// Authenticate user, get challenge message
257+
const { authBlumMetamaskMessage } = await restClient.request(
258+
GraphQL.AuthBlumMetamaskMessageDocument,
259+
{
260+
address: userAccount.address,
261+
input: {
262+
telegramID: userTelegramID,
263+
sign: 'field_for_future_sign',
264+
},
265+
},
266+
)
267+
268+
// Sign the auth challenge message with the user private key
269+
const userSignature = await userAccount.signMessage({ message: authBlumMetamaskMessage })
270+
271+
// Send the signed challenge message to the server to get the auth token (JWT)
272+
const { authBlumMetamaskLogin } = await restClient.request(
273+
GraphQL.AuthBlumMetamaskLoginDocument,
274+
{
275+
session: adminSession,
276+
input: {
277+
authMessage: authBlumMetamaskMessage,
278+
sign: userSignature,
279+
},
280+
},
281+
)
282+
283+
const userSession = authBlumMetamaskLogin.session
284+
console.log('User session (save this!):', userSession)
285+
286+
const userProfile = authBlumMetamaskLogin.user_profile
287+
console.log('User profile:', userProfile)
288+
289+
// Fetch user details to verify JWT session works
290+
const { userProfile: fetchedUserProfile } = await restClient.request(
291+
GraphQL.GetUserProfileDocument,
292+
{
293+
session: userSession,
294+
},
295+
)
296+
console.log('Fetched user profile:', fetchedUserProfile)
297+
}
298+
299+
main().catch((error) => {
300+
console.error(error)
301+
})
302+
303+
```

0 commit comments

Comments
 (0)