Revoking Google Identity (Sign in with Google version 2022) in Server Side - google-signin

Background
Google is kicking people out of Google Sign-in JavaScript library (platform.js) and pushing people to migration Sign In With Google by Google Identity Services library (gsi/client). (Migration Guide)
Anyone must go through this migration by March 2023. The new flows are cool (e.g. One-tap) and should make life easier.
Problem
In the new flow, Authentication and Authorization are separated! If you just need basic scopes (e.g. email, basic profile), then Authentication should be enough.
With that, you get an ID Token (a JWT) that you can verify on server-side.
The problem is, revoking this token (as listed in Revocation Methods) can only be done either manually by the user in their own Google Account, or it should be done on client-side. No server-side option is present.
The Case
Our platform supports sign in with Google, Apple, and email/password.
The same user uses Google Sign In on Web and Apple Sign In on their iPhone. (same email address.)
Per the forces of Apple, since June 30, 2022, we should provide a delete account option.
User signs in with Apple Sign In to our platform and requests deleting their account.
We can (and must, again per Apple) revoke Sign In with Apple by calling Apple's Server-to-Server Revoke Tokens endpoint. But Google doesn't provide such an option for ID-Token. :(
Any idea how to solve this?

Current alternatives
1) Use Authorization and store access_token and refresh_token
(Per Google Identity > OAuth 2.0 > Server-side Web Apps > Revoking a token) OAuth revoke takes an access token or refresh token.
The old gapi library of Google Sign In for Web, was granting access token on sign in. The new one doesn't. So we have to explicitly ask for an access token via Authorization flows, and store it/refresh-token in the DB and maintain it. That's overkill, but works.
2) Do it in client-side and cover the most, not all
It can be done on the client-side when the request for delete-account is sent to the server. However, it only covers signed-in-with-Google users. This means that the mentioned use case (signed in with Apple) wouldn't be covered. But, hey, it's a cheap and fast solution!

Related

If anyone take my Google Sign in token, can he or she sign in via that access token?

I am learning react-js development, from this course I learned that I can use Firebase and Google sign as a third part storage service and sign in verification service, I draw a sign in steps with drawio diagram, as diagram below if someone take my (2) Google verification token or (6) Firebase access token can he or she sign in my website on his machine by that two tokens before expired ?
clarification about google token or firebase token security level.
That's a pretty standard OAuth flow. Firebase JS SDK does the same under the hood when you call signInWithPopup():
Getting user's access token after user's approval
Signing in with the response (see sign in with OAuth credential)
Yes, if I somehow get your Google Access Token (2), I can use it to access your account's data (for the scopes it has access to). Similarly, Firebase tokens are generally used as a Bearer token that means anyone in possession of the token gets access to the resources.
But chances of someone getting these tokens are slim to none (unless they have physical access to user's computer). As long as users do not share these tokens or any malicious script tries to read them, this flow has no issues.

Sign out user via REST HTTP API

I can sign in users to Firebase using this HTTP API:
How do I sign out users, so that the Firebase idToken and refreshToken can no longer be used?
Also, how long is the refreshToken valid for?
If my user does not use my app for weeks, can I still use the refreshToken or will I need to get a fresh Google Sign In idToken and exchange it for a Firebase (idToken, refreshToken) pair via the /identitytoolkit/v3/relyingparty/verifyAssertion API?
I don't believe there is a sign out endpoint. You could try doing a redirect to https://accounts.google.com/Logout but I suspect that is signing out from all Google services which might not be a great idea.
The whole point of Refresh Tokens is that they can be used to access resources whether or not the user is present and signed in, so your comment "How do I sign out users, so that the Firebase idToken and refreshToken can no longer be used" is an oxymoron.
A Refresh Token is theoretically valid until a user specifically revokes it, but your app should code for the possibility that Google has expired it.
The client cannot directly revoke the ID token via the REST API, but both the Firebase Auth client SDKs (ex: Android) and the Auth Admin SDK do support it. So if your client platform isn't supported, but you are able to create a small server implementation (maybe through Firebase/Cloud Functions), you can create an HTTP endpoint that triggers ID token revocation.

How to provide Firebase authentication interface for a third party?

("Superpoints" and "Megashop" used below are fake business names)
I am using Firebase Auth to authenticate users in my (Android) app ("Superpoints"). My users can earn points for using my app, they can later spend when paying for something.
I want to integrate with a partner ("Megashop") in the following way:
Alice opens the Superpoints app on her Android phone.
In the app she clicks on "Megashop campaigns".
A web browser or a web view (whichever is fine for me) for superpoints.megashop.com opens. The opened page has a button like "Login with Superpoints account".
Alice clicks on "Login with Superpoints account" and provides her credentials (this can be email+password, log in with phone number, log in with Google Account).
The system checks if Alice's accounts exists in my user database and sends back the response to Megashop with Alice's Superpoints membership ID and her balance (for example: "{ memberId: 100500, points: 42 }").
After Alice purchases something in Megashop, their checkout hook sends a request to HTTPS endpoint for a cloud function that adds an amount of points (for example, 250 points) to Alice's balance (something like https://app.superpoints.com/accrual?partner=megashop&memberId=100500&points=250).
On my app's website, I do the authentication using FirebaseUI Auth, in the app I'm also using FirebaseUI (library for Android).
Now finally the questions: How to authenticate my users on a third party's site? What are the best practices? Should I build some kind of a gateway for the third party, or is there an easier way for doing that?
This is a classic case of OAuth.
Firebase Auth, as far as I know, does not support acting as a OAuth provider.

Replacing Google Sign-In for Websites with Cloud Identity-Aware Proxy

There's an open feature request for Metabase to support IAP. I took a stab at it, and have a Clojure implementation of the steps detailed in Securing your app with signed headers (i.e. verify token header, verify token payload, retrieve user identity).
But this question isn't necessarily specific to Metabase. The general idea is to replace Google Sign-In and only use only IAP signed headers for authentication and user creation in an application on Google App Engine (specifically, GAE flex environment).
The "problem" is that the user identity information from the IAP token looks like: {"email":"alice#example.com","sub":"accounts.google.com:118133858486581853996"}. I also came across Using special URLs, but this returns something like: {"email":"accounts.google.com:USER_EMAIL","sub":"accounts.google.com:118133858486581853996"}.
With a Google Sign-In token, I can obtain values for given_name and family_name along with email, which means I can fetch-or-create a valid Metabase user. Is there a way to get the first and last name via the JWT sub, (i.e. accounts.google.com:118133858486581853996)?
Hm, if they have a public profile you can pass the number after "accounts.google.com:" to https://developers.google.com/+/web/api/rest/latest/people/get . Unfortunately, you won't be able to authenticate to that API as the user, since IAP doesn't currently provide a way to call let users delegate access to call Google APIs. (You'll have to use a service account to call that API.)
The other solution would be, if IAP provided a way to a) specify additional scopes in its OAuth request to Google, and if it then b) passed additional claims from the OIDC token into the IAP JWT, you'd be able to configure IAP to request the "profile" scope. However, IAP currently only requests the "email" and "openid" scopes, and doesn't have a mechanism for specifying additional scopes.
-- Matthew, Google Cloud IAP engineering

Check if user has my Facebook app installed

My website uses a Facebook application which sends notifications to its users.
On one of my pages the user can subscribe or unsubscribe (depending on whether or not he is subscribed).
Therefore I want to check if the user is using my app. How can I do that? I guess I could do the following to see if the app can access the data:
FacebookClient c = new FacebookClient(accessTokenClaim.Value);
c.AppId = MYAPPID;
c.AppSecret = MYAPPSECRET;
dynamic access = c.Get("/me/permissions");
if(access != null)
{
//has access
}
The one thing I don't like about this, however, is the fact that I have to use an access token to see if the user has the app installed.
I would prefer not to use access tokens since they tend to expire.
In my database I store the Facebook userIds of all my website users.
Therefore it would be ideal if I could do something like the following:
/get?appinstalled&userid=USERID
What would be the best way to go about this?
To get the current user ID - to compare it with your DB - you will have to access FB graph API using an access token. So I think there is no way to find any info about the user without using FB access tokens.
Edit: And do not worry about the expiration of the token, FB SDK will handle that for you. i.e. it will refresh automatically by the SDK. Here:
Facebook's official SDKs manage the lifetime of tokens for you. When
using iOS, Android or our JavaScript SDK, the SDK will handle making
sure that tokens are refreshed before they expire.
And
Access tokens on the web often have a lifetime of about two hours, but
will automatically be refreshed when required. If you want to use
access tokens for longer-lived web apps, especially server side, you
need to generate a long-lived token. A long-lived token generally
lasts about 60 days.

Resources