Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
custom jwt flow
  • Loading branch information
ikethirdweb committed Oct 17, 2023
commit 45ba5a3ae19764eaa65864ed6a9c9fb6c8d15ddf
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
AuthOptions,
EmbeddedWalletConnectionArgs,
EmbeddedWalletConnectorOptions,
OauthOption,
Expand All @@ -7,7 +8,12 @@ import type { Chain } from "@thirdweb-dev/chains";
import { Connector, normalizeChainId } from "@thirdweb-dev/wallets";
import { providers, Signer } from "ethers";
import { utils } from "ethers";
import { sendEmailOTP, socialLogin, validateEmailOTP } from "./embedded/auth";
import {
customJwt,
sendEmailOTP,
socialLogin,
validateEmailOTP,
} from "./embedded/auth";
import { getEthersSigner } from "./embedded/signer";
import { logoutUser } from "./embedded/helpers/auth/logout";
import {
Expand All @@ -30,11 +36,16 @@ export class EmbeddedWalletConnector extends Connector<EmbeddedWalletConnectionA
this.email = getConnectedEmail();
}

async connect(options?: { email?: string; chainId?: number }) {
async connect(
options?: { chainId?: number } & Omit<
EmbeddedWalletConnectionArgs,
"email"
>,
) {
const connected = await this.isConnected();

if (!connected) {
throw new Error("Not connected");
// const;
}

if (options?.chainId) {
Expand Down Expand Up @@ -114,6 +125,30 @@ export class EmbeddedWalletConnector extends Connector<EmbeddedWalletConnectionA
return { success: true };
}

async verifyAuth(authOptions: AuthOptions) {
try {
const resp = await customJwt(authOptions, this.options.clientId);
this.email = resp.email;
} catch (error) {
console.error(`Error while verifying auth: ${error}`);
this.disconnect();
throw error;
}

try {
await this.getSigner();
this.emit("connected");
} catch (error) {
if (error instanceof Error) {
return { error: error.message };
} else {
return { error: "Error getting the signer" };
}
}

return { success: true };
}

async disconnect(): Promise<void> {
clearConnectedEmail();
await logoutUser(this.options.clientId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,11 @@ import { isDeviceSharePresentForUser } from "./helpers/storage/local";
import { getCognitoUser, setCognitoUser } from "./helpers/storage/state";
import { SendEmailOtpReturnType } from "@thirdweb-dev/wallets";
import { InAppBrowser } from "react-native-inappbrowser-reborn";
import { OauthOption } from "../types";
import { ROUTE_HEADLESS_GOOGLE_LOGIN } from "./helpers/constants";
import { AuthOptions, OauthOption } from "../types";
import {
ROUTE_AUTH_JWT_CALLBACK,
ROUTE_HEADLESS_GOOGLE_LOGIN,
} from "./helpers/constants";

export async function sendEmailOTP(
email: string,
Expand Down Expand Up @@ -196,3 +199,46 @@ export async function socialLogin(oauthOptions: OauthOption, clientId: string) {
);
}
}

export async function customJwt(authOptions: AuthOptions, clientId: string) {
const { jwt, authProvider } = authOptions;

const resp = await fetch(ROUTE_AUTH_JWT_CALLBACK, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jwt,
authProvider,
developerClientId: clientId,
}),
});
if (!resp.ok) {
const { error } = await resp.json();
throw new Error(`JWT authentication error: ${error} `);
}

try {
const { verifiedToken, verifiedTokenJwtString } = await resp.json();

const toStoreToken: AuthStoredTokenWithCookieReturnType["storedToken"] = {
jwtToken: verifiedToken.rawToken,
authProvider: verifiedToken.authProvider,
authDetails: {
...verifiedToken.authDetails,
email: verifiedToken.authDetails.email,
},
developerClientId: verifiedToken.developerClientId,
cookieString: verifiedTokenJwtString,
shouldStoreCookieString: false,
isNewUser: verifiedToken.isNewUser,
};

await postPaperAuth(toStoreToken, clientId);

return { verifiedToken, email: verifiedToken.authDetails.email };
} catch (e) {
throw new Error(
`Malformed response from post authentication: ${JSON.stringify(e)}`,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const ROUTE_INIT_RECOVERY_CODE_FREE_WALLET = `${ROUTE_2022_08_12_API_BASE
export const ROUTE_STORE_USER_SHARES = `${ROUTE_2022_08_12_API_BASE_PATH}/embedded-wallet/store-shares`;
export const ROUTE_GET_USER_SHARES = `${ROUTE_2022_08_12_API_BASE_PATH}/embedded-wallet/get-shares`;
export const ROUTE_VERIFY_THIRDWEB_CLIENT_ID = `${ROUTE_2022_08_12_API_BASE_PATH}/embedded-wallet/verify-thirdweb-client-id`;
export const ROUTE_AUTH_JWT_CALLBACK = `${ROUTE_2022_08_12_API_BASE_PATH}/embedded-wallet/jwt-callback`;

export const ROUTE_HEADLESS_GOOGLE_LOGIN = `${BASE_URL}/api/2022-08-12/embedded-wallet/headless-login-link`;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ export interface EmbeddedWalletConnectorOptions {
styles?: PaperConstructorType<RecoveryShareManagement>["styles"];
}

export interface AuthOptions {
jwt: string;
authProvider: string;
recoveryCode: string;
}

export interface EmbeddedWalletConnectionArgs {
email?: string;
authOptions?: AuthOptions;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ export type EmbeddedWalletConfig = {
// @default true - set false to disable
email?: boolean;

// @default { providers: ['google'] } - set false to disable
oauthOptions?:
| {
providers: OAuthProvider[];
Expand Down