Skip to content

Commit

Permalink
[RN] Adds the ability to login with any arbitrary login payload (#2074)
Browse files Browse the repository at this point in the history
  • Loading branch information
iketw authored Dec 13, 2023
1 parent 699f31c commit 07fbb79
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 10 deletions.
13 changes: 13 additions & 0 deletions .changeset/perfect-cups-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@thirdweb-dev/react-native": patch
---

Adds the ability to login with any arbitrary login payload

```typescript
await embeddedWallet.authenticate({
strategy: "auth_endpoint",
payload: "SOME_STRING",
encryptionKey: "",
});
```
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
AuthEndpointOptions,
AuthOptions,
AuthParams,
AuthResult,
Expand All @@ -11,6 +12,7 @@ import type { Chain } from "@thirdweb-dev/chains";
import { providers, Signer } from "ethers";
import { utils } from "ethers";
import {
authEndpoint,
customJwt,
sendVerificationEmail,
socialLogin,
Expand Down Expand Up @@ -101,7 +103,13 @@ export class EmbeddedWalletConnector extends Connector<EmbeddedWalletConnectionA
case "jwt": {
return this.customJwt({
jwt: params.jwt,
password: params.encryptionKey || "",
password: params.encryptionKey,
});
}
case "auth_endpoint": {
return this.authEndpoint({
payload: params.payload,
encryptionKey: params.encryptionKey,
});
}
default:
Expand Down Expand Up @@ -230,6 +238,33 @@ export class EmbeddedWalletConnector extends Connector<EmbeddedWalletConnectionA
}
}

private async authEndpoint(
authOptions: AuthEndpointOptions,
): Promise<AuthResult> {
try {
const { verifiedToken, email } = await authEndpoint(
authOptions,
this.options.clientId,
);
this.email = email;
return {
user: {
status: UserWalletStatus.LOGGED_IN_WALLET_INITIALIZED,
recoveryShareManagement:
verifiedToken.authDetails.recoveryShareManagement,
},
isNewUser: verifiedToken.isNewUser,
needsRecoveryCode:
verifiedToken.authDetails.recoveryShareManagement ===
RecoveryShareManagement.USER_MANAGED,
};
} catch (error) {
console.error(`Error while verifying auth_endpoint auth: ${error}`);
this.disconnect();
throw error;
}
}

async disconnect(): Promise<void> {
clearConnectedEmail();
clearConnectedAuthStrategy();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,17 @@ import { Auth } from "aws-amplify";
import {
DOMAIN_URL_2023,
EWS_VERSION_HEADER,
ROUTE_AUTH_ENDPOINT_CALLBACK,
ROUTE_AUTH_JWT_CALLBACK,
ROUTE_HEADLESS_OAUTH_LOGIN,
THIRDWEB_SESSION_NONCE_HEADER,
} from "./helpers/constants";
import { AuthOptions, OauthOption, VerifiedTokenResponse } from "../types";
import {
AuthEndpointOptions,
AuthOptions,
OauthOption,
VerifiedTokenResponse,
} from "../types";
import { InAppBrowser } from "react-native-inappbrowser-reborn";
import { createErrorMessage } from "./helpers/errors";
import {
Expand Down Expand Up @@ -307,7 +313,62 @@ export async function customJwt(authOptions: AuthOptions, clientId: string) {
return { verifiedToken, email: verifiedToken.authDetails.email };
} catch (e) {
throw new Error(
createErrorMessage("Malformed response from post authentication", e),
createErrorMessage("Malformed response from post jwt authentication", e),
);
}
}

export async function authEndpoint(
authOptions: AuthEndpointOptions,
clientId: string,
) {
const { payload, encryptionKey } = authOptions;

const resp = await fetch(ROUTE_AUTH_ENDPOINT_CALLBACK, {
method: "POST",
headers: {
"Content-Type": "application/json",
[EWS_VERSION_HEADER]: reactNativePackageVersion,
[BUNDLE_ID_HEADER]: appBundleId,
[THIRDWEB_SESSION_NONCE_HEADER]: ANALYTICS.nonce,
},
body: JSON.stringify({
payload: payload,
developerClientId: clientId,
}),
});
if (!resp.ok) {
const error = await resp.json();
throw new Error(
`Custom auth endpoint authentication error: ${error.message}`,
);
}

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

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

await postPaperAuthUserManaged(toStoreToken, clientId, encryptionKey);

return { verifiedToken, email: verifiedToken.authDetails.email };
} catch (e) {
throw new Error(
createErrorMessage(
"Malformed response from post auth_endpoint authentication",
e,
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ async function getRecoveryCode(
storedToken.authDetails.recoveryShareManagement ===
RecoveryShareManagement.CLOUD_MANAGED
) {
if (storedToken.authProvider === AuthProvider.CUSTOM_JWT) {
if (
storedToken.authProvider === AuthProvider.CUSTOM_JWT ||
storedToken.authProvider === AuthProvider.CUSTOM_AUTH_ENDPOINT
) {
if (!recoveryCode) {
throw new Error(
`GetRecoveryCode error: ${ErrorMessages.missingRecoveryCode}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const ROUTE_STORE_USER_SHARES = `${ROUTE_2023_10_20_API_BASE_PATH}/embedd
export const ROUTE_GET_USER_SHARES = `${ROUTE_2023_10_20_API_BASE_PATH}/embedded-wallet/embedded-wallet-shares`;
export const ROUTE_VERIFY_THIRDWEB_CLIENT_ID = `${ROUTE_2023_10_20_API_BASE_PATH}/embedded-wallet/verify-thirdweb-client-id`;
export const ROUTE_AUTH_JWT_CALLBACK = `${ROUTE_2023_10_20_API_BASE_PATH}/embedded-wallet/validate-custom-jwt`;
export const ROUTE_AUTH_ENDPOINT_CALLBACK = `${ROUTE_2023_10_20_API_BASE_PATH}/embedded-wallet/validate-custom-auth-endpoint`;

export const ROUTE_USER_MANAGED_OTP = `${ROUTE_2023_10_20_API_BASE_PATH}/embedded-wallet/send-user-managed-email-otp`;
export const ROUTE_VALIDATE_USER_MANAGED_OTP = `${ROUTE_2023_10_20_API_BASE_PATH}/embedded-wallet/validate-thirdweb-email-otp`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ export interface AuthOptions {
password: string;
}

export interface AuthEndpointOptions {
payload: string;
encryptionKey: string;
}

export type SendEmailOtpReturnType = {
isNewUser: boolean;
isNewDevice: boolean;
Expand Down Expand Up @@ -73,11 +78,18 @@ type JwtAuthParams = {
encryptionKey: string;
};

type AuthEndpointParams = {
strategy: "auth_endpoint";
payload: string;
encryptionKey: string;
};

// this is the input to 'authenticate'
export type AuthParams =
| EmailVerificationAuthParams
| SocialAuthParams
| JwtAuthParams;
| JwtAuthParams
| AuthEndpointParams;

// TODO typed based off AuthParams["strategy"]
export type AuthResult = {
Expand Down
9 changes: 4 additions & 5 deletions packages/unity-js-bridge/src/thirdweb-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,7 @@ class ThirdwebBridge implements TWBridge {
chainId: chainIdNumber,
authResult,
});
}
else {
} else {
throw new Error(
"Invalid auth provider: " + authOptionsParsed.authProvider,
);
Expand Down Expand Up @@ -680,11 +679,11 @@ class ThirdwebBridge implements TWBridge {
strategy: "encryptedJson",
password,
});
} catch(e) {
} catch (e) {
console.warn(e);
return localWallet;
}

return localWallet;
}

Expand Down Expand Up @@ -787,7 +786,7 @@ class ThirdwebBridge implements TWBridge {
return JSON.stringify({ result: res }, bigNumberReplacer);
}

public async getEmail(){
public async getEmail() {
const embeddedWallet = this.walletMap.get(
walletIds.embeddedWallet,
) as EmbeddedWallet;
Expand Down

0 comments on commit 07fbb79

Please sign in to comment.