Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<pwa-auth> – enable Sign in with Google with a reduced response when strict privacy mode (Block third-party cookies or InPrivate browsing) is used (until we switch to Google Identity Services for Web). #3343

Closed
wants to merge 10 commits into from
Closed
41 changes: 39 additions & 2 deletions components/pwa-auth/src/google-provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import { SignInResult } from "./signin-result";
import { SignInProvider } from "./signin-provider";

const JP = (...a) => { try { return JSON.parse(...a); } catch (_) { return undefined; } };

const any = AbortSignal.any ?? (S => {
const C = new AbortController(); for (const s of S) { if (s === undefined) continue; if (s.aborted) { C.abort(); break; } s.addEventListener('abort', () => C.abort(), { once: true, signal: C.signal }); }
return C.signal;
});

const event = (name, { source: on = globalThis, map = x => x, find = e => true, signal, default: { value: V, error: E } = {} } = {}) => new Promise(async (Y, N) => { const s = signal; const A = new AbortController();
const a = async () => (V === undefined ? N(E) : Y(await V) ); if (s?.aborted) return (A.abort(), a()); s?.addEventListener?.('abort', a, { once: true });
const l = async e => { e = map(e); if (!find(e)) return; A.abort(); Y(await e); }; on.addEventListener (name, l, { signal: any([ s, A.signal ]) });
});

const wait = {};


export class GoogleProvider implements SignInProvider {

static readonly apiUrl = "https://apis.google.com/js/api:client.js";
Expand Down Expand Up @@ -66,8 +81,30 @@ export class GoogleProvider implements SignInProvider {
}

// Otherwise, kick off the OAuth flow.
return auth.signIn()
.then(user => this.getSignInResultFromUser(user));
// (Use only a reduced response when people Block third-party cookies or use InPrivate browsing.)
const I = auth.signIn();
const Y = async signal => {
const z = await event('message', { signal, map: e => JP(e.data), find: d => d?.params?.type == 'authResult' });
Copy link
Author

@CetinSert CetinSert Sep 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.data

  {
    "method": "fireIdpEvent",
    "params": {
      "type": "authResult",
      "clientId": "57804582347-fjts48vf74aujonq0akjmh16ta0kuuak.apps.googleusercontent.com",
      "id": "auth395061",
      "authResult": {
        "scope": "email profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile openid",
        "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjE3MjdiNmI0OTQwMmI5Y2Y5NWJlNGU4ZmQzOGFhN2U3YzExNjQ0YjEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXpwIjoiNTc4MDQ1ODIzNDctZmp0czQ4dmY3NGF1am9ucTBha2ptaDE2dGEwa3V1YWsuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiI1NzgwNDU4MjM0Ny1manRzNDh2Zjc0YXVqb25xMGFram1oMTZ0YTBrdXVhay5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjEwMjYyODQ1NTQ5MDkwMTk0NTI2MiIsImVtYWlsIjoiY2V0aW4uc2VydEBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiaWF0IjoxNjYwODc2MTcxLCJleHAiOjE2NjA4Nzk3NzEsImp0aSI6IjAyOTRlYzhiMTViOGMxNDYyNGM3NDZhMGYzZjNkOTZmODczMTA5ZmUifQ.da6OcBgxGctw4eKXVn6vquTwj3mSRnkUwQFFCPpJVRDC6qeGop07vfSwhz2FceR9_QbWt9nFGdbeELY8X47EDARUbCzfNRH80IUQ2BnZ62X3Y-Zrzb8KK1QXR8sBZuA2HubtF6hJ-Rz4FIBAH8nTVdoK68JPIX_kY_3CH_WfcYeZwgLaUj2z9vLo6ScI2l_opGdc12JiyaqSLWAy_HHfY4ooyogIoeiCn8fxTuOYLx3PFoOXyYilf39zhELR70G28kl_Q3rzXyMB4_1xTRGLNn5p76l8HPEhB-xs0-agNsEpjn79GaCDIOQfI5_qNXtUVd88OL7wyJ4s3JolUh7v2w",
        "login_hint": "AJDLj6JTnD9r5nUgBTjHPh9yEse-ZVOAAuXsa0TMIG26duGuqQvjeAHqDZsUu1-mHw6Et__QhInJSlsBKxsE7MtamnbsupuUog",
        "client_id": "57804582347-fjts48vf74aujonq0akjmh16ta0kuuak.apps.googleusercontent.com"
      }
    }
  },

const id_token = z.params.authResult.id_token;
const j = await fetch(`https://oauth2.googleapis.com/tokeninfo?${new URLSearchParams({ id_token })}`).then(f => f.json());
const x = {
email: j.email,
idToken: id_token,
provider: 'Google',
error: null,
providerData: j
};
try { return this.getSignInResultFromUser(await I); }
catch (q) { return x ; }
};
const N = async signal => { event('message', { signal, map: e => JP(e.data), find: d => d?.params?.type == 'idpError' }).then(_ => wait.twice = true);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.data

  {
    "method": "fireIdpEvent",
    "params": {
      "type": "idpError",
      "error": "Cookies are not enabled in current environment."
    },
    "rpcToken": "1227886743.6877475"
  },

/**/ let e; e = await event('error', { signal });
if (wait.twice) { wait.twice = false; e = await event('error', { signal }); }
throw new Error('User cancelled the flow!');
};
let E; const C = new AbortController();
let R; try { R = await Promise.race([ Y(C.signal), N(C.signal) ]); } catch (e) { E = e; }; C.abort(); if (E !== undefined) throw E;
return R;
}

private getSignInResultFromUser(user: gapi.auth2.GoogleUser): SignInResult {
Expand Down