Search code examples
node.jsexpressapple-sign-in

"Sign in with Apple" redirects to a blank white page on PWA


I've implemented "Sign in with Apple" on my site. When I try it on my phone, it redirects me to a blank white page with the same URL as the redirect_uri I've configured.

I can't find any info on why this is happening. What's a possible fix?

UPDATE

It seems as if Apple JS SDK is creating a FORM HTML DOM element, sets the POST URL of the FORM to point to the redirect_uri, and finally programmatically clicks form.submit(). This for some reason causes the page to navigate to the redirect_uri and show the POST response as a new page.

I figured this out by tracking the Apple JS SDK in the debugger.

Here is my code

//----  Frontend ----

AppleID.auth.init({
    clientId : '<client_id>',
    scope : 'email',
    redirectURI : 'mySite.com/apple_auth',
    state : 'origin:web',
    nonce : Date.now(),
    //usePopup : true //not using this one. When false or undefined, Apple will make a POST request to the defined redirect_uri
})


// Listen for authorization success.
document.addEventListener('AppleIDSignInOnSuccess', (event) => {
    // Handle successful response.
    console.log(event.detail.data);
});

// Listen for authorization failures.
document.addEventListener('AppleIDSignInOnFailure', (event) => {
    // Handle error.
    console.log(event.detail.error);
});

//...

myButton.onClick = ()=>{
    try {
        var res = await AppleID.auth.signIn()
    } catch(err) {
        var x = 0
    }
}
//----  Backend ----

var appleSignin = require("apple-signin-auth")

app.express.post('/apple_auth', async (req, res)=>{
    var body = req.body
    try {
        const appleRes = await appleSignin.verifyIdToken(
            body.id_token, // We need to pass the token that we wish to decode.
            {
                audience: '<client_id', // client id - The same one we used  on the frontend, this is the secret key used for encoding and decoding the token.
                ignoreExpiration: true, // Token will not expire unless you manually do so.
            }
        )
        
        //do something with the Apple response
    } catch (err) {
        // Token is not verified
        console.error(err)
    }
})

Solution

    1. From the documentation...

      The HTTP body contains the result parameters with a content-type of application/x-www-form-urlencoded.

      Make sure you've configured the urlencoded() body-parsing middleware in your Express app.

      app.use(express.urlencoded());
      
    2. Make sure you check for errors and actually send a response from your /apple_auth Express route

      const { code, id_token, state, user, error } = req.body;
      if (error) {
        return res.status(500).send(error);
      }
      try {
        const appleRes = await appleSignin.verifyIdToken(id_token, {
          audience: "<client_id>",
          ignoreExpiration: true,
        });
      
        // do something with the Apple response, then send a response
        res.send(appleRes.sub);
      } catch (err) {
        console.error(err);
        res.sendStatus(500); // send a 500 response status
      }