Skip to content

Commit 5e39ca6

Browse files
Ethelladevin-ai-integration[bot]sherzod-bakhodirov
authored
Devin/1744245477 implement login with popup v2 (#879)
* Implement loginWithPopupV2 method in React Native OAuth extensions Co-Authored-By: [email protected] <[email protected]> * Fix loginWithPopupV2 implementation to use Verify method Co-Authored-By: [email protected] <[email protected]> * Adding babel plugins * bump compiler options to es2022 * bump esbuild target to es2022 * remove local forage * bump expo-web-browser * remove unused dependency * add back rn * mock localforage * revert build target * es2022 * Remove Extension class and rename InternalExtension to MagicExtension Co-Authored-By: [email protected] <[email protected]> * remove static field * remove static field * update yarn.lock * fix test * fix tests * update yarn.lock * Revert "Remove Extension class and rename InternalExtension to MagicExtension…" This reverts commit d3d0911. * bump target to es 2022 * update yarn.lock * update yarn.lock * remove static plugin * remove crypto * update yarn.lock * feat: hardcode embedded wallet url * remove console --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: sherzod-bakhodirov <[email protected]>
1 parent 3a3fbaf commit 5e39ca6

File tree

22 files changed

+177
-954
lines changed

22 files changed

+177
-954
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
presets: ['module:@react-native/babel-preset'],
3+
};

packages/@magic-ext/react-native-bare-oauth/package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,11 @@
2626
]
2727
},
2828
"dependencies": {
29-
"crypto-js": "^4.2.0",
30-
"react-native-device-info": "^10.3.0"
29+
"react-native-inappbrowser-reborn": "^3.7.0"
3130
},
3231
"devDependencies": {
3332
"@magic-sdk/react-native-bare": "^30.4.2",
34-
"@magic-sdk/types": "^24.21.0",
35-
"@types/crypto-js": "~4.2.0",
36-
"react-native-inappbrowser-reborn": "^3.7.0"
33+
"@magic-sdk/types": "^24.21.0"
3734
},
3835
"peerDependencies": {
3936
"@magic-sdk/react-native-bare": ">=13.0.0",

packages/@magic-ext/react-native-bare-oauth/src/crypto.ts

Lines changed: 0 additions & 79 deletions
This file was deleted.

packages/@magic-ext/react-native-bare-oauth/src/index.ts

Lines changed: 35 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { InAppBrowser } from 'react-native-inappbrowser-reborn';
22
import { Extension } from '@magic-sdk/react-native-bare';
3-
import { getBundleId } from 'react-native-device-info';
4-
import { createCryptoChallenge } from './crypto';
53
import {
64
OAuthErrorData,
75
OAuthPayloadMethods,
86
OAuthRedirectConfiguration,
97
OAuthRedirectError,
108
OAuthRedirectResult,
9+
OAuthRedirectStartResult,
1110
} from './types';
1211

1312
export class OAuthExtension extends Extension.Internal<'oauth'> {
@@ -23,18 +22,38 @@ export class OAuthExtension extends Extension.Internal<'oauth'> {
2322
public loginWithPopup(configuration: OAuthRedirectConfiguration) {
2423
return this.utils.createPromiEvent<OAuthRedirectResult>(async (resolve, reject) => {
2524
try {
26-
const { provider, query, redirectURI } = await createURI.call(this, configuration);
27-
const url = `https://auth.magic.link/v1/oauth2/${provider}/start?${query}`;
25+
const startPayload = this.utils.createJsonRpcRequestPayload(OAuthPayloadMethods.Start, [
26+
{
27+
...configuration,
28+
apiKey: this.sdk.apiKey,
29+
platform: 'rn',
30+
},
31+
]);
32+
33+
const result = await this.request<OAuthRedirectStartResult | OAuthRedirectError>(startPayload);
34+
const successResult = result as OAuthRedirectStartResult;
35+
const errorResult = result as OAuthRedirectError;
36+
37+
if (errorResult.error) {
38+
reject(
39+
this.createError<OAuthErrorData>(errorResult.error, errorResult.error_description ?? 'An error occurred.', {
40+
errorURI: errorResult.error_uri,
41+
provider: errorResult.provider,
42+
}),
43+
);
44+
return;
45+
}
46+
47+
if (!successResult?.oauthAuthoriationURI) {
48+
reject(this.createError<object>('NO_AUTH_URI', 'No authorization URI was returned', {}));
49+
return;
50+
}
2851

29-
/**
30-
* Response Type Inspired by:
31-
* https://docs.expo.io/versions/latest/sdk/webbrowser/#returns
32-
*/
33-
const res = await InAppBrowser.openAuth(url, redirectURI, {});
52+
const url = successResult.oauthAuthoriationURI;
53+
const res = await InAppBrowser.openAuth(url, configuration.redirectURI, {});
3454

3555
if (res.type === 'success') {
3656
const queryString = new URL(res.url).search;
37-
3857
resolve(getResult.call(this, queryString.toString()));
3958
} else {
4059
reject(this.createError<object>(res.type, 'User has cancelled the authentication', {}));
@@ -50,66 +69,14 @@ export class OAuthExtension extends Extension.Internal<'oauth'> {
5069
}
5170
}
5271

53-
const OAUTH_REDIRECT_METADATA_KEY = 'oauth_redirect_metadata';
54-
55-
export async function createURI(this: OAuthExtension, configuration: OAuthRedirectConfiguration) {
56-
// Bust any old, in-progress OAuth flows.
57-
await this.utils.storage.removeItem(OAUTH_REDIRECT_METADATA_KEY);
58-
59-
// Unpack configuration, generate crypto values, and persist to storage.
60-
const { provider, redirectURI, scope, loginHint } = configuration;
61-
const { verifier, challenge, state } = await createCryptoChallenge();
62-
const bundleId = getBundleId();
63-
64-
/* Stringify for RN Async storage */
65-
const storedData = JSON.stringify({
66-
verifier,
67-
state,
68-
});
69-
70-
await this.utils.storage.setItem(OAUTH_REDIRECT_METADATA_KEY, storedData);
71-
72-
// Formulate the initial redirect query to Magic's OAuth hub.
73-
// Required fields:
74-
// - `magic_api_key`
75-
// - `magic_challenge`
76-
// - `state`
77-
// - `redirect_uri`
78-
// - `platform`
79-
// Optional fields:
80-
// - `bundleId`
81-
82-
const query = [
83-
`magic_api_key=${encodeURIComponent(this.sdk.apiKey)}`,
84-
`magic_challenge=${encodeURIComponent(challenge)}`,
85-
`state=${encodeURIComponent(state)}`,
86-
`platform=${encodeURIComponent('rn')}`,
87-
scope && `scope=${encodeURIComponent(scope.join(' '))}`,
88-
redirectURI && `redirect_uri=${encodeURIComponent(redirectURI)}`,
89-
loginHint && `login_hint=${encodeURIComponent(loginHint)}`,
90-
bundleId && `bundleId=${encodeURIComponent(bundleId)}`,
91-
].reduce((prev, next) => (next ? `${prev}&${next}` : prev));
92-
93-
return {
94-
query,
95-
provider,
96-
redirectURI,
97-
};
98-
}
99-
10072
export function getResult(this: OAuthExtension, queryString: string) {
10173
return this.utils.createPromiEvent<OAuthRedirectResult>(async (resolve, reject) => {
102-
const json: string = (await this.utils.storage.getItem(OAUTH_REDIRECT_METADATA_KEY)) as string;
103-
104-
const { verifier, state } = JSON.parse(json);
105-
106-
// Remove the save OAuth state from storage, it stays in memory now...
107-
this.utils.storage.removeItem(OAUTH_REDIRECT_METADATA_KEY);
108-
109-
const parseRedirectResult = this.utils.createJsonRpcRequestPayload(OAuthPayloadMethods.ParseRedirectResult, [
110-
queryString,
111-
verifier,
112-
state,
74+
const parseRedirectResult = this.utils.createJsonRpcRequestPayload(OAuthPayloadMethods.Verify, [
75+
{
76+
authorizationResponseParams: queryString,
77+
magicApiKey: this.sdk.apiKey,
78+
platform: 'rn',
79+
},
11380
]);
11481

11582
// Parse the result, which may contain an OAuth-formatted error.

packages/@magic-ext/react-native-bare-oauth/src/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { MagicUserMetadata } from '@magic-sdk/types';
22

33
export enum OAuthPayloadMethods {
4-
ParseRedirectResult = 'magic_oauth_parse_redirect_result',
4+
Start = 'magic_oauth_login_with_redirect_start',
5+
Verify = 'magic_oauth_login_with_redirect_verify',
6+
Popup = 'magic_oauth_login_with_popup',
57
}
68

79
export type OAuthProvider =
@@ -107,3 +109,9 @@ export enum OAuthErrorCode {
107109
ServerError = 'server_error',
108110
TemporarilyUnavailable = 'temporarily_unavailable',
109111
}
112+
113+
export interface OAuthRedirectStartResult {
114+
oauthAuthoriationURI?: string;
115+
useMagicServerCallback?: boolean;
116+
shouldReturnURI?: boolean;
117+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
presets: ['babel-preset-expo'],
3+
};

packages/@magic-ext/react-native-expo-oauth/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,17 @@
2626
]
2727
},
2828
"dependencies": {
29-
"@magic-sdk/types": "^10.0.0",
30-
"crypto-js": "^4.2.0",
31-
"expo-application": "^5.0.1",
32-
"expo-web-browser": ">=12.0.0"
29+
"expo-web-browser": "14.0.2"
3330
},
3431
"devDependencies": {
3532
"@magic-sdk/react-native-expo": "^30.4.2",
33+
"@magic-sdk/types": "^24.18.2",
34+
"@react-native-async-storage/async-storage": "^2.1.2",
3635
"@types/crypto-js": "~4.2.0"
3736
},
3837
"peerDependencies": {
39-
"@magic-sdk/react-native-expo": ">=13.0.0"
38+
"@magic-sdk/react-native-expo": ">=13.0.0",
39+
"@magic-sdk/types": "^24.18.2",
40+
"@react-native-async-storage/async-storage": "^2.1.2"
4041
}
4142
}

packages/@magic-ext/react-native-expo-oauth/src/crypto.ts

Lines changed: 0 additions & 79 deletions
This file was deleted.

0 commit comments

Comments
 (0)