Skip to content

Add useAuthToken hook for in-app wallet authentication #7120

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

Merged
Merged
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
3 changes: 2 additions & 1 deletion packages/thirdweb/src/exports/react.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ export type {

// wallet hooks
export { useActiveWallet } from "../react/core/hooks/wallets/useActiveWallet.js";
export { useAdminWallet } from "../react/core/hooks/wallets/useAdminWallet.js";
export { useActiveWalletChain } from "../react/core/hooks/wallets/useActiveWalletChain.js";
export { useActiveWalletConnectionStatus } from "../react/core/hooks/wallets/useActiveWalletConnectionStatus.js";
export { useActiveAccount } from "../react/core/hooks/wallets/useActiveAccount.js";
export { useAdminWallet } from "../react/core/hooks/wallets/useAdminWallet.js";
export { useAuthToken } from "../react/core/hooks/wallets/useAuthToken.js";
export { useAutoConnect } from "../react/native/hooks/wallets/useAutoConnect.js";
export { useConnect } from "../react/core/hooks/wallets/useConnect.js";
export { useConnectedWallets } from "../react/core/hooks/wallets/useConnectedWallets.js";
Expand Down
3 changes: 2 additions & 1 deletion packages/thirdweb/src/exports/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ export type { MediaRendererProps } from "../react/web/ui/MediaRenderer/types.js"

// wallet hooks
export { useActiveWallet } from "../react/core/hooks/wallets/useActiveWallet.js";
export { useAdminWallet } from "../react/core/hooks/wallets/useAdminWallet.js";
export { useActiveWalletChain } from "../react/core/hooks/wallets/useActiveWalletChain.js";
export { useActiveWalletConnectionStatus } from "../react/core/hooks/wallets/useActiveWalletConnectionStatus.js";
export { useActiveAccount } from "../react/core/hooks/wallets/useActiveAccount.js";
export { useAdminWallet } from "../react/core/hooks/wallets/useAdminWallet.js";
export { useAuthToken } from "../react/core/hooks/wallets/useAuthToken.js";
export { useAutoConnect } from "../react/web/hooks/wallets/useAutoConnect.js";
export { useConnect } from "../react/core/hooks/wallets/useConnect.js";
export { useConnectedWallets } from "../react/core/hooks/wallets/useConnectedWallets.js";
Expand Down
41 changes: 41 additions & 0 deletions packages/thirdweb/src/react/core/hooks/wallets/useAuthToken.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useActiveAccount } from "./useActiveAccount.js";
import { useActiveWallet } from "./useActiveWallet.js";

/**
* A hook that returns the authentication token (JWT) for the currently active wallet.
* This token can be used to authorize API calls to your backend server.
*
* @returns The JWT string if the active wallet is an in-app wallet and matches the active account, null otherwise
*
* @example
* ```tsx
* function MyComponent() {
* const authToken = useAuthToken();
*
* const fetchData = async () => {
* const response = await fetch('https://api.example.com/data', {
* headers: {
* 'Authorization': `Bearer ${authToken}`
* }
* });
* // ... handle response
* };
* }
* ```
*
* @wallet
*/
export function useAuthToken() {
const activeWallet = useActiveWallet();
const activeAccount = useActiveAccount();
// if the active wallet is an in-app wallet and the active account is the same as the active wallet's account, return the auth token for the in-app wallet
if (
activeWallet?.getAuthToken &&
activeAccount &&
activeAccount.address === activeWallet.getAccount()?.address
) {
return activeWallet.getAuthToken();
}
// all other wallets don't expose an auth token for now
return null;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { SocialAuthOption } from "../../../../wallets/types.js";
import type { Account } from "../../../interfaces/wallet.js";
import type { ClientScopedStorage } from "../authentication/client-scoped-storage.js";
import type {
AuthArgsType,
AuthLoginReturnType,
Expand Down Expand Up @@ -38,4 +39,5 @@ export interface InAppConnector {
linkProfile(args: AuthArgsType): Promise<Profile[]>;
unlinkProfile(args: Profile): Promise<Profile[]>;
getProfiles(): Promise<Profile[]>;
storage: ClientScopedStorage;
}
15 changes: 15 additions & 0 deletions packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@
let adminAccount: Account | undefined = undefined; // Admin account if smartAccountOptions were provided with connection
let chain: Chain | undefined = undefined;
let client: ThirdwebClient | undefined;
let authToken: string | null = null;

return {
id: walletId,
getAuthToken: () => authToken,
subscribe: emitter.subscribe,
getChain() {
if (!chain) {
Expand Down Expand Up @@ -114,6 +116,12 @@
account = connectedAccount;
adminAccount = _adminAccount;
chain = connectedChain;
try {
authToken = await connector.storage.getAuthCookie();
} catch (error) {
console.error("Failed to retrieve auth token:", error);
authToken = null;
}
trackConnect({
client: options.client,
ecosystem,
Expand Down Expand Up @@ -168,6 +176,12 @@
account = connectedAccount;
adminAccount = _adminAccount;
chain = connectedChain;
try {
authToken = await connector.storage.getAuthCookie();
} catch (error) {
console.error("Failed to retrieve auth token:", error);
authToken = null;
}
trackConnect({
client: options.client,
ecosystem,
Expand All @@ -194,6 +208,7 @@
account = undefined;
adminAccount = undefined;
chain = undefined;
authToken = null;

Check warning on line 211 in packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts

View check run for this annotation

Codecov / codecov/patch

packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts#L211

Added line #L211 was not covered by tests
emitter.emit("disconnect", undefined);
},
switchChain: async (newChain) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type NativeConnectorOptions = {
export class InAppNativeConnector implements InAppConnector {
private client: ThirdwebClient;
private ecosystem?: Ecosystem;
private storage: ClientScopedStorage;
public storage: ClientScopedStorage;
private passkeyDomain?: string;
private wallet?: IWebWallet;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export class InAppWebConnector implements InAppConnector {
private client: ThirdwebClient;
private ecosystem?: Ecosystem;
private querier: InAppWalletIframeCommunicator<AuthQuerierTypes>;
private storage: ClientScopedStorage;
public storage: ClientScopedStorage;

private wallet?: IWebWallet;
/**
Expand Down
12 changes: 11 additions & 1 deletion packages/thirdweb/src/wallets/interfaces/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,18 @@ export type Wallet<TWalletId extends WalletId = WalletId> = {
* This is useful for smart wallets to get the underlying personal account
*/
getAdminAccount?: () => Account | undefined;
};

/**
* Get the authentication token for the wallet.
*
* This method is not available for on all wallets. This method will be `undefined` if the wallet does not support it.
* @example
* ```ts
* const authToken = await wallet.getAuthToken();
* ```
*/
getAuthToken?: () => string | null;
};
/**
* Account interface
*
Expand Down
Loading