Skip to content

Commit b65c507

Browse files
committed
Add Login component with Google authentication support
1 parent f72823c commit b65c507

File tree

10 files changed

+154
-20
lines changed

10 files changed

+154
-20
lines changed
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { THIRDWEB_CLIENT } from "@/lib/client";
2+
import { getDomain } from "@/lib/constants";
3+
import { SERVER_WALLET } from "@/lib/server-wallet";
4+
5+
import { Login } from "thirdweb";
6+
7+
export const { GET, POST } = Login.Server.toNextJsHandler(
8+
Login.Server.createAuthHandler({
9+
client: THIRDWEB_CLIENT,
10+
domain: getDomain() ?? "",
11+
serverWallet: SERVER_WALLET,
12+
}),
13+
);
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { CodeExample } from "@/components/code/code-example";
2+
import ThirdwebProvider from "@/components/thirdweb-provider";
3+
import { metadataBase } from "@/lib/constants";
4+
import type { Metadata } from "next";
5+
import { PageLayout } from "../../../components/blocks/APIHeader";
6+
import { BasicLoginExample } from "../../../components/login/basic-example";
7+
8+
export const metadata: Metadata = {
9+
metadataBase,
10+
title: "Login | thirdweb Connect",
11+
description: "TODO",
12+
};
13+
14+
export default function Page() {
15+
return (
16+
<ThirdwebProvider>
17+
<PageLayout
18+
title="Login"
19+
description={
20+
<>Let users login to your app using any authentication provider.</>
21+
}
22+
docsLink="https://portal.thirdweb.com/typescript/v5/auth?utm_source=playground"
23+
>
24+
<div className="flex flex-col gap-14">
25+
<CodeExample
26+
lang="ts"
27+
code={"TODO"}
28+
preview={<BasicLoginExample />}
29+
/>
30+
</div>
31+
</PageLayout>
32+
</ThirdwebProvider>
33+
);
34+
}

apps/playground-web/src/app/engine/actions.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
"use server";
22

3+
import { THIRDWEB_CLIENT } from "@/lib/client";
4+
import { SERVER_WALLET } from "@/lib/server-wallet";
35
import { Engine, defineChain, encode, getContract } from "thirdweb";
46
import { multicall } from "thirdweb/extensions/common";
57
import * as ERC20 from "thirdweb/extensions/erc20";
68
import * as ERC1155 from "thirdweb/extensions/erc1155";
7-
import { THIRDWEB_CLIENT } from "../../lib/client";
8-
const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string;
9-
const ENGINE_VAULT_ACCESS_TOKEN = process.env
10-
.ENGINE_VAULT_ACCESS_TOKEN as string;
11-
12-
const serverWallet = Engine.serverWallet({
13-
address: BACKEND_WALLET_ADDRESS,
14-
client: THIRDWEB_CLIENT,
15-
vaultAccessToken: ENGINE_VAULT_ACCESS_TOKEN,
16-
});
179

1810
export async function airdrop_tokens_with_engine(params: {
1911
contractAddress: string;
@@ -44,7 +36,7 @@ export async function airdrop_tokens_with_engine(params: {
4436
data,
4537
});
4638

47-
const res = await serverWallet.enqueueTransaction({ transaction: tx });
39+
const res = await SERVER_WALLET.enqueueTransaction({ transaction: tx });
4840

4941
return res.transactionId;
5042
}
@@ -82,7 +74,7 @@ export async function mint_erc1155_nft_with_engine(params: MintNFTParams) {
8274
to: params.toAddress,
8375
supply: BigInt(params.metadataWithSupply.supply),
8476
});
85-
const res = await serverWallet.enqueueTransaction({ transaction: tx });
77+
const res = await SERVER_WALLET.enqueueTransaction({ transaction: tx });
8678

8779
return res.transactionId;
8880
}
@@ -106,7 +98,7 @@ export async function claim_erc1155_nft_with_engine(params: ClaimNFTParams) {
10698
tokenId: BigInt(params.tokenId),
10799
quantity: BigInt(params.quantity),
108100
});
109-
const res = await serverWallet.enqueueTransaction({ transaction: tx });
101+
const res = await SERVER_WALLET.enqueueTransaction({ transaction: tx });
110102

111103
return res.transactionId;
112104
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"use client";
2+
3+
import { THIRDWEB_CLIENT } from "@/lib/client";
4+
import { useRef, useState } from "react";
5+
import { Login } from "thirdweb";
6+
import { sepolia } from "thirdweb/chains";
7+
import { Button } from "../ui/button";
8+
import { Input } from "../ui/input";
9+
10+
export function BasicLoginExample() {
11+
const [account, setAccount] = useState<Login.Client.LoginResult>();
12+
const otpRef = useRef<HTMLInputElement>(null);
13+
14+
if (!account) {
15+
return (
16+
<div className="flex flex-col gap-4">
17+
<Button
18+
onClick={async () => {
19+
const account = await Login.Client.login({
20+
type: "google",
21+
client: THIRDWEB_CLIENT,
22+
baseURL: "http://localhost:3000/connect/login/api/auth",
23+
chain: sepolia,
24+
});
25+
setAccount(account);
26+
}}
27+
>
28+
Login with Google
29+
</Button>
30+
</div>
31+
);
32+
}
33+
34+
if (account.status === "requires_otp") {
35+
return (
36+
<div className="flex flex-col gap-4">
37+
<Input ref={otpRef} placeholder="OTP" />
38+
<Button
39+
onClick={async () => {
40+
if (!otpRef.current?.value) {
41+
return;
42+
}
43+
setAccount(await account.verifyOtp(otpRef.current?.value));
44+
}}
45+
>
46+
Verify OTP
47+
</Button>
48+
</div>
49+
);
50+
}
51+
52+
return (
53+
<div className="flex flex-col gap-4">
54+
<p>Logged in as: {account.id}</p>
55+
<Button
56+
onClick={async () => {
57+
const jwt = await account.getJWT();
58+
alert(`JWT: ${jwt}`);
59+
}}
60+
>
61+
Get JWT
62+
</Button>
63+
<Button
64+
onClick={async () => {
65+
await account.logout();
66+
setAccount(undefined);
67+
}}
68+
>
69+
Logout
70+
</Button>
71+
</div>
72+
);
73+
}

apps/playground-web/src/lib/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export const metadataBase = process.env.VERCEL_ENV
44
? new URL("https://playground.thirdweb.com")
55
: undefined;
66

7-
const getDomain = () => {
7+
export const getDomain = () => {
88
if (process.env.VERCEL_ENV === "production") {
99
return "thirdweb.com";
1010
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import "server-only";
2+
import { Engine } from "thirdweb";
3+
import { sepolia } from "thirdweb/chains";
4+
import { THIRDWEB_CLIENT } from "./client";
5+
6+
const BACKEND_WALLET_ADDRESS = process.env.ENGINE_BACKEND_WALLET as string;
7+
const ENGINE_VAULT_ACCESS_TOKEN = process.env
8+
.ENGINE_VAULT_ACCESS_TOKEN as string;
9+
10+
export const SERVER_WALLET = Engine.serverWallet({
11+
address: BACKEND_WALLET_ADDRESS,
12+
client: THIRDWEB_CLIENT,
13+
vaultAccessToken: ENGINE_VAULT_ACCESS_TOKEN,
14+
chain: sepolia,
15+
});
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export { login, type LoginOptions as LoginParams } from "./login.js";
1+
export { login, type LoginOptions, type LoginResult } from "./login.js";

packages/thirdweb/src/login/client/login.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export type LoginOptions = (
3030
}
3131
) & {
3232
client: ThirdwebClient;
33+
chain: Chain;
3334
options?: {
3435
sponsorGas?: boolean;
3536
redirectUrl?: string;
@@ -39,10 +40,12 @@ export type LoginOptions = (
3940
baseURL?: string;
4041
};
4142

43+
export type LoginResult = Awaited<ReturnType<typeof login>>;
44+
4245
export async function login(loginOptions: LoginOptions) {
4346
const IAW = inAppWallet({
4447
auth: {
45-
mode: "redirect",
48+
mode: "popup",
4649
options: [],
4750
redirectUrl: loginOptions.options?.redirectUrl,
4851
passkeyDomain: loginOptions.options?.passkeyDomain,
@@ -61,6 +64,7 @@ export async function login(loginOptions: LoginOptions) {
6164
client: loginOptions.client,
6265
strategy: "jwt",
6366
jwt: loginOptions.jwt,
67+
chain: loginOptions.chain,
6468
});
6569

6670
return mapAccount(account, IAW, loginOptions.baseURL);
@@ -86,6 +90,7 @@ export async function login(loginOptions: LoginOptions) {
8690
phoneNumber: loginOptions.phoneNumber,
8791
verificationCode,
8892
client: loginOptions.client,
93+
chain: loginOptions.chain,
8994
});
9095

9196
return mapAccount(account, IAW, loginOptions.baseURL);
@@ -114,6 +119,7 @@ export async function login(loginOptions: LoginOptions) {
114119
email: loginOptions.email,
115120
verificationCode,
116121
client: loginOptions.client,
122+
chain: loginOptions.chain,
117123
});
118124

119125
return mapAccount(account, IAW, loginOptions.baseURL);
@@ -142,6 +148,7 @@ export async function login(loginOptions: LoginOptions) {
142148
const account = await IAW.connect({
143149
client: loginOptions.client,
144150
strategy: loginOptions.type,
151+
chain: loginOptions.chain,
145152
});
146153

147154
return mapAccount(account, IAW, loginOptions.baseURL);
@@ -229,7 +236,7 @@ function mapAccount(
229236
const payloadResponse = await authClient("/payload", {
230237
query: {
231238
address: account.address,
232-
chainId: IAW.getChain()?.id,
239+
chainId: IAW.getChain()?.id?.toString(),
233240
},
234241
});
235242
if (payloadResponse.error) {

packages/thirdweb/src/login/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export * as Client from "./client/index.js";
22
export * as Server from "./server/index.js";
33

44
// client
5-
export { login, type LoginOptions as LoginParams } from "./client/login.js";
5+
export { login, type LoginOptions, type LoginResult } from "./client/login.js";
66

77
// server
88
export {

packages/thirdweb/src/login/server/auth-handler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,14 @@ export function createAuthHandler({
8080
method: "GET",
8181
query: z.object({
8282
address: z.string().refine(isAddress, "Invalid address"),
83-
chainId: z.number().optional(),
83+
chainId: z.string().optional(),
8484
}),
8585
},
8686
(ctx) => {
8787
const { address, chainId } = ctx.query;
8888
return twAuth.generatePayload({
8989
address,
90-
chainId: chainId ? Number(chainId) : undefined,
90+
chainId: chainId ? Number.parseInt(chainId) : undefined,
9191
});
9292
},
9393
);

0 commit comments

Comments
 (0)