Skip to content

Add login module with client and server authentication capabilities #7106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/thirdweb/.size-limit.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
{
"name": "thirdweb (esm)",
"path": "./dist/esm/exports/thirdweb.js",
"limit": "60 kB",
"limit": "90 kB",
"import": "*"
},
{
"name": "thirdweb (cjs)",
"path": "./dist/cjs/exports/thirdweb.js",
"limit": "350 kB"
"limit": "375 kB"
},
{
"name": "thirdweb (minimal + tree-shaking)",
Expand Down
94 changes: 31 additions & 63 deletions packages/thirdweb/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
"import": "./dist/esm/exports/extensions/*.js",
"default": "./dist/cjs/exports/extensions/*.js"
},
"./login": {
"types": "./dist/types/exports/login.d.ts",
"import": "./dist/esm/exports/login.js",
"default": "./dist/cjs/exports/login.js"
},
"./pay": {
"types": "./dist/types/exports/pay.d.ts",
"import": "./dist/esm/exports/pay.js",
Expand Down Expand Up @@ -147,66 +152,27 @@
},
"typesVersions": {
"*": {
"adapters/*": [
"./dist/types/exports/adapters/*.d.ts"
],
"auth": [
"./dist/types/exports/auth.d.ts"
],
"chains": [
"./dist/types/exports/chains.d.ts"
],
"contract": [
"./dist/types/exports/contract.d.ts"
],
"deploys": [
"./dist/types/exports/deploys.d.ts"
],
"event": [
"./dist/types/exports/event.d.ts"
],
"extensions/*": [
"./dist/types/exports/extensions/*.d.ts"
],
"pay": [
"./dist/types/exports/pay.d.ts"
],
"react": [
"./dist/types/exports/react.d.ts"
],
"react-native": [
"./dist/types/exports/react.native.d.ts"
],
"rpc": [
"./dist/types/exports/rpc.d.ts"
],
"storage": [
"./dist/types/exports/storage.d.ts"
],
"transaction": [
"./dist/types/exports/transaction.d.ts"
],
"utils": [
"./dist/types/exports/utils.d.ts"
],
"wallets": [
"./dist/types/exports/wallets.d.ts"
],
"wallets/*": [
"./dist/types/exports/wallets/*.d.ts"
],
"modules": [
"./dist/types/exports/modules.d.ts"
],
"social": [
"./dist/types/exports/social.d.ts"
],
"ai": [
"./dist/types/exports/ai.d.ts"
],
"bridge": [
"./dist/types/exports/bridge.d.ts"
]
"adapters/*": ["./dist/types/exports/adapters/*.d.ts"],
"auth": ["./dist/types/exports/auth.d.ts"],
"chains": ["./dist/types/exports/chains.d.ts"],
"contract": ["./dist/types/exports/contract.d.ts"],
"deploys": ["./dist/types/exports/deploys.d.ts"],
"event": ["./dist/types/exports/event.d.ts"],
"extensions/*": ["./dist/types/exports/extensions/*.d.ts"],
"login": ["./dist/types/exports/login.d.ts"],
"pay": ["./dist/types/exports/pay.d.ts"],
"react": ["./dist/types/exports/react.d.ts"],
"react-native": ["./dist/types/exports/react.native.d.ts"],
"rpc": ["./dist/types/exports/rpc.d.ts"],
"storage": ["./dist/types/exports/storage.d.ts"],
"transaction": ["./dist/types/exports/transaction.d.ts"],
"utils": ["./dist/types/exports/utils.d.ts"],
"wallets": ["./dist/types/exports/wallets.d.ts"],
"wallets/*": ["./dist/types/exports/wallets/*.d.ts"],
"modules": ["./dist/types/exports/modules.d.ts"],
"social": ["./dist/types/exports/social.d.ts"],
"ai": ["./dist/types/exports/ai.d.ts"],
"bridge": ["./dist/types/exports/bridge.d.ts"]
}
},
"browser": {
Expand Down Expand Up @@ -241,6 +207,7 @@
"@walletconnect/ethereum-provider": "2.20.1",
"@walletconnect/sign-client": "2.20.1",
"abitype": "1.0.8",
"better-call": "1.0.9",
"cross-spawn": "7.0.6",
"fuse.js": "7.1.0",
"input-otp": "^1.4.1",
Expand All @@ -251,7 +218,8 @@
"prompts": "2.4.2",
"toml": "3.0.0",
"uqr": "0.1.2",
"viem": "2.28.1"
"viem": "2.28.1",
"zod": "3.24.3"
},
"peerDependencies": {
"@aws-sdk/client-lambda": "^3",
Expand Down Expand Up @@ -324,7 +292,7 @@
"bench:compare": "bun run ./benchmarks/run.ts",
"bench": "vitest -c ./test/vitest.config.ts bench",
"format": "biome format ./src --write",
"lint": "knip && biome check ./src && tsc --project ./tsconfig.build.json --module esnext --noEmit",
"lint": "knip && biome check ./src && tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --noEmit",
"fix": "biome check ./src --fix",
"knip": "knip",
"build:generate": "bun scripts/generate/generate.ts",
Expand All @@ -335,7 +303,7 @@
"build": "pnpm clean && pnpm build:types && pnpm build:cjs && pnpm build:esm",
"build:cjs": "tsc --noCheck --project ./tsconfig.build.json --module commonjs --outDir ./dist/cjs --verbatimModuleSyntax false && printf '{\"type\":\"commonjs\"}' > ./dist/cjs/package.json",
"build:esm": "tsc --noCheck --project ./tsconfig.build.json --module es2020 --outDir ./dist/esm && printf '{\"type\": \"module\",\"sideEffects\":false}' > ./dist/esm/package.json",
"build:types": "tsc --project ./tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
"build:types": "tsc --project ./tsconfig.build.json --module nodenext --moduleResolution nodenext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
"clean": "rimraf dist",
"size": "size-limit",
"test:watch": "vitest -c ./test/vitest.config.ts dev",
Expand Down
1 change: 1 addition & 0 deletions packages/thirdweb/src/exports/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "../login/index.js";
5 changes: 5 additions & 0 deletions packages/thirdweb/src/exports/thirdweb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ export * as Insight from "../insight/index.js";
*/
export * as Engine from "../engine/index.js";

/**
* LOGIN
*/
export * as Login from "../login/index.js";

/**
* WALLETS
*/
Expand Down
201 changes: 201 additions & 0 deletions packages/thirdweb/src/login/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
## Installation

```bash
npm install thirdweb
```

## Usage

```typescript
// Import everything
import { Login } from "thirdweb";

// Or import specific parts
import { login, createAuthHandler } from "thirdweb";
```

## Client-Side Authentication

The client-side authentication system provides methods for handling user authentication in the browser.

### Basic Usage

```typescript
import { Login } from "thirdweb/login";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent import path

The import path here doesn't match the example shown in the basic usage section (line 11).

-import { Login } from "thirdweb/login";
+import { Login } from "thirdweb";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { Login } from "thirdweb/login";
import { Login } from "thirdweb";
🤖 Prompt for AI Agents
In packages/thirdweb/src/login/README.md at line 24, the import path for the
Login module is inconsistent with the example shown at line 11. Update the
import statement to match the path used in the basic usage section to maintain
consistency and avoid confusion.


// Email login
const result = await Login.Client.login({
type: "email",
email: "[email protected]",
client: thirdwebClient,
});

// Handle OTP verification
if (result.status === "requires_otp") {
const account = await result.verifyOtp("123456");
}

// Phone login
const result = await Login.Client.login({
type: "phone",
phoneNumber: "+1234567890",
client: thirdwebClient,
});

// Wallet login
const result = await Login.Client.login({
type: "wallet",
wallet: userWallet,
chain: selectedChain,
client: thirdwebClient,
});

// JWT login
const result = await Login.Client.login({
type: "jwt",
jwt: "your-jwt-token",
client: thirdwebClient,
});
```

### Authentication Options

```typescript
type LoginOptions = {
client: ThirdwebClient;
options?: {
sponsorGas?: boolean; // Enable gas sponsorship
redirectUrl?: string; // Custom redirect URL
passkeyDomain?: string; // Domain for passkey authentication
storage?: AsyncStorage; // Custom storage implementation
};
baseURL?: string; // Base URL for your authentication server
};
```

### Authenticated Account Features

Once authenticated, you get access to the following features:

```typescript
const account = await Login.Client.login({...});

// Get JWT token
const jwt = await account.getJWT();

// Send a transaction
await account.sendTransaction(transaction);

// Send batch transactions
await account.sendBatchTransaction([transaction1, transaction2]);

// Sign messages
await account.signMessage(message);

// Sign typed data
await account.signTypedData(typedData);

// Logout
await account.logout();
```

## Server-Side Authentication

The server-side authentication system provides utilities for handling authentication on the server.

### Basic Setup

```typescript
import { Login } from "thirdweb/login";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent import path

The import path here is also inconsistent with the basic usage example.

-import { Login } from "thirdweb/login";
+import { Login } from "thirdweb";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { Login } from "thirdweb/login";
-import { Login } from "thirdweb/login";
+import { Login } from "thirdweb";
🤖 Prompt for AI Agents
In packages/thirdweb/src/login/README.md at line 109, the import path for the
Login module is inconsistent with the basic usage example. Update the import
statement to match the correct and consistent path used in the rest of the
documentation, ensuring uniformity across all examples.


// Initialize the server-side authentication handler
const authHandler = Login.Server.createAuthHandler({
// Your configuration options
});
```

### Framework Integrations

The package provides built-in integrations for popular frameworks:

```typescript
import { Login } from "thirdweb/login";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent import path

The import path here is inconsistent with the basic usage example.

-import { Login } from "thirdweb/login";
+import { Login } from "thirdweb";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { Login } from "thirdweb/login";
-import { Login } from "thirdweb/login";
+import { Login } from "thirdweb";
🤖 Prompt for AI Agents
In packages/thirdweb/src/login/README.md at line 122, the import path for the
Login module is inconsistent with the basic usage example. Update the import
statement to match the correct and consistent path used elsewhere in the
documentation, ensuring uniformity across all examples.


// Express.js integration
app.all("/api/auth/*", Login.Server.toNodeHandler(authHandler));

// Next.js integration
// /app/api/auth/[...all]/route.ts
export const { GET, POST } = Login.Server.toNextJsHandler(authHandler);


// Hono integration
import { Hono } from "hono";
import { serve } from "@hono/node-server"

const app = new Hono();

app.on(["GET", "POST"], "/api/auth/**", (c) => authHandler.handler(c.req.raw));

serve(app);
```

### Required Endpoints

The server implements the following endpoints:

1. `/api/auth/payload` - Generate authentication payload
2. `/api/auth/login` - Handle login requests
3. `/api/auth/logout` - Handle logout requests
4. `/api/auth/is-logged-in` - Verify authentication status

(You can change the base path (`/api/auth`) by passing the `basePath` option to the `createAuthHandler` function.)

### Server-Side Features

- JWT validation and generation
- Session management
- Authentication state verification
- Secure token storage
- Rate limiting support
- Framework integrations

## Security Considerations

- JWT tokens are automatically refreshed when expired
- Sensitive operations require proper authentication
- Session management is handled securely
- Gas sponsorship can be enabled for better UX

## Best Practices

1. Always use HTTPS for authentication endpoints
2. Implement proper error handling
3. Use secure storage for sensitive data
4. Implement rate limiting for authentication attempts
5. Keep JWT tokens secure and handle them properly

## Error Handling

The login system provides detailed error messages for various scenarios:
- Invalid credentials
- Expired tokens
- Network issues
- Invalid authentication methods

## TypeScript Support

Full TypeScript support is included with proper type definitions for all authentication methods and responses.

## API Reference

### Client Exports

- `login(options: LoginOptions)`: Initiates the login process
- `LoginParams`: Type definition for login options

### Server Exports

- `createAuthHandler(options: CreateAuthHandlerOptions)`: Creates an authentication handler
- `toNodeHandler(handler)`: Converts auth handler to be used in Node.js servers (e.g. Express, Fastify, etc.)
- `toNextJsHandler(handler)`: Converts auth handler to Next.js API route handler
1 change: 1 addition & 0 deletions packages/thirdweb/src/login/client/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { login, type LoginOptions as LoginParams } from "./login.js";
Loading
Loading