I’m creating a react native mobile application and recently applied the customer account API.
So, as for the otp authentication i need to use the webview so as in my website after login it redirects to acount/orders page in my mobile application it is doing the same and then after 2 seconds it then redirects to the mobile application. Which should not happen and it should directly open the mobile application.
i’m attaching the part of the code so that you get the source and tell me where i am going wrong
async function handleNav(url: string) {
console.log("NAV URL:", url);
/**
* STEP A — Capture OAuth redirect
*/
if (url.startsWith(REDIRECT_URI)) {
const codeMatch = url.match(/[?&]code=([^&]+)/);
const code = codeMatch ? decodeURIComponent(codeMatch[1]) : null;
if (code) {
console.log("✅ OAuth code received:", code);
await exchangeCodeForToken(code);
}
return;
}
/**
* STEP B — Detect OTP login success
*/
const loggedIn =
url.includes("/account") &&
!url.includes("login") &&
!url.includes("authorize");
if (loggedIn && !pkceStarted.current) {
pkceStarted.current = true;
console.log("🎉 OTP Login Success → Starting OAuth");
const verifier = generateCodeVerifier();
const challenge = generateCodeChallenge(verifier);
await AsyncStorage.setItem("PKCE_VERIFIER", verifier);
// Discover OAuth endpoints
const discovery = await fetch(
`https://${SHOP_DOMAIN}/.well-known/openid-configuration`
).then(res => res.json());
const authorizeUrl =
`${discovery.authorization_endpoint}?` +
`client_id=${CLIENT_ID}` +
`&response_type=code` +
`&scope=${encodeURIComponent(SCOPES)}` +
`&redirect_uri=${encodeURIComponent(REDIRECT_URI)}` +
`&code_challenge=${challenge}` +
`&code_challenge_method=S256`;
console.log("🔐 Loading OAuth URL:", authorizeUrl);
setWebViewUrl(authorizeUrl);
return;
}
}
async function exchangeCodeForToken(code: string) {
console.log("🔁 Exchanging code for token...");
// 1. Get PKCE verifier
const verifier = await AsyncStorage.getItem("PKCE_VERIFIER");
if (!verifier) {
throw new Error("PKCE verifier missing");
}
// 2.Discover token endpoint
const discovery = await fetch(
`https://${SHOP_DOMAIN}/.well-known/openid-configuration`
).then(res => res.json());
// 3. Build body
const body = new URLSearchParams();
body.append("grant_type", "authorization_code");
body.append("client_id", CLIENT_ID);
body.append("redirect_uri", REDIRECT_URI);
body.append("code", code);
body.append("code_verifier", verifier);
// 4. Call token endpoint
const response = await fetch(discovery.token_endpoint, {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
"user-agent": "mimosa-react-native",
},
body: body.toString(),
});
if (!response.ok) {
const err = await response.text();
throw new Error(err);
}
const {
access_token,
refresh_token,
expires_in,
id_token,
} = await response.json();
// 5. Persist tokens
await AsyncStorage.multiSet([
["ACCESS_TOKEN", access_token],
["REFRESH_TOKEN", refresh_token],
["TOKEN_EXPIRES_AT", String(Date.now() + expires_in * 1000)],
["ID_TOKEN", id_token],
]);
console.log("✅ Tokens stored successfully");
// 6. Navigate only AFTER success
navigation.reset({
index: 0,
routes: [{ name: "MainTabs" }],
});
}
return (
<WebView
source={{ uri: webViewUrl }}
sharedCookiesEnabled
thirdPartyCookiesEnabled
onNavigationStateChange={(nav: { url: string; }) => handleNav(nav.url)}
/>
);
}
