1
1
import { InAppBrowser } from 'react-native-inappbrowser-reborn' ;
2
2
import { Extension } from '@magic-sdk/react-native-bare' ;
3
- import { getBundleId } from 'react-native-device-info' ;
4
- import { createCryptoChallenge } from './crypto' ;
5
3
import {
6
4
OAuthErrorData ,
7
5
OAuthPayloadMethods ,
8
6
OAuthRedirectConfiguration ,
9
7
OAuthRedirectError ,
10
8
OAuthRedirectResult ,
9
+ OAuthRedirectStartResult ,
11
10
} from './types' ;
12
11
13
12
export class OAuthExtension extends Extension . Internal < 'oauth' > {
@@ -23,18 +22,38 @@ export class OAuthExtension extends Extension.Internal<'oauth'> {
23
22
public loginWithPopup ( configuration : OAuthRedirectConfiguration ) {
24
23
return this . utils . createPromiEvent < OAuthRedirectResult > ( async ( resolve , reject ) => {
25
24
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
+ }
28
51
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 , { } ) ;
34
54
35
55
if ( res . type === 'success' ) {
36
56
const queryString = new URL ( res . url ) . search ;
37
-
38
57
resolve ( getResult . call ( this , queryString . toString ( ) ) ) ;
39
58
} else {
40
59
reject ( this . createError < object > ( res . type , 'User has cancelled the authentication' , { } ) ) ;
@@ -50,66 +69,14 @@ export class OAuthExtension extends Extension.Internal<'oauth'> {
50
69
}
51
70
}
52
71
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
-
100
72
export function getResult ( this : OAuthExtension , queryString : string ) {
101
73
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
+ } ,
113
80
] ) ;
114
81
115
82
// Parse the result, which may contain an OAuth-formatted error.
0 commit comments