I’m trying to implement a passwordless authentication with the new Customer Account API in Next.js.
I’m facing problems in the local environment because when I get redirected, I get an access denied error.
The steps I’m following are these:
-
I have ngrok installed, and I create a “tunnel domain”.
-
I enable the Customer Account API in the Shopify dashboard.
a) I set the client type to Public
b) I copy my client_id
c) I add the ngrok tunned domain to application setup, callback and javascript origin.
- I defined the function to call when I click on my account button like this:
import { generateCodeVerifier } from "./verifierAndChallenge";
import { generateCodeChallenge } from "./verifierAndChallenge";
const loginCustomer = async (e) => {
e.preventDefault();
const loginUrl = new URL(`${process.env.NEXT_PUBLIC_SHOPIFY_ACCOUNT_API_URL}/auth/oauth/authorize`);
loginUrl.searchParams.append("scope", "openid email https://api.customers.com/auth/customer.graphql");
loginUrl.searchParams.append("client_id", process.env.NEXT_PUBLIC_SHOPIFY_CUSTOMER_ACCOUNT_ACCESS_TOKEN);
loginUrl.searchParams.append("response_type", "code");
loginUrl.searchParams.append("redirect_uri", `https://f501-90-166-179-8.ngrok-free.app/authorize`);
// For extra security use the following (must do, but later)
// loginUrl.searchParams.append("state", await generateState());
// loginUrl.searchParams.append("nonce", await generateNonce(25));
// Public client
const verifier = await generateCodeVerifier();
const challenge = await generateCodeChallenge(verifier);
localStorage.setItem("code-verifier", verifier);
loginUrl.searchParams.append("code_challenge", challenge);
loginUrl.searchParams.append("code_challenge_method", "S256");
window.location.href = loginUrl.toString();
};
export default loginCustomer;
And the preceding code uses this one:
export async function generateCodeVerifier() {
const rando = generateRandomCode();
return base64UrlEncode(rando);
}
export async function generateCodeChallenge(codeVerifier) {
const digestOp = await crypto.subtle.digest({ name: "SHA-256" }, new TextEncoder().encode(codeVerifier));
const hash = convertBufferToString(digestOp);
return base64UrlEncode(hash);
}
function generateRandomCode() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return String.fromCharCode.apply(null, Array.from(array));
}
function base64UrlEncode(str) {
const base64 = btoa(str);
// This is to ensure that the encoding does not have +, /, or = characters in it.
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
function convertBufferToString(hash) {
const uintArray = new Uint8Array(hash);
const numberArray = Array.from(uintArray);
return String.fromCharCode(...numberArray);
}
But when I click on the my account button, the url show this error:
And this is what the request looks like:
Could anyone point me in the right direction?
Thanks a lot!
