Why I'm not getting the nonce in the ID token when using the Sign In with Google One Tap UX in ITP browsers / Safari? - google-oauth

I have a test web app, with the Sign In with Google button + One Tap UX configured with a data-nonce :
<div
id="g_id_onload"
data-client_id="<%=google_client_id%>"
data-context="signin"
data-ux_mode="popup"
data-login_uri="<%=site_address%>/sign-in-with-google-callback"
data-nonce="<%=idTokenNonce%>"
data-itp_support="true"
></div>
<div
class="g_id_signin"
data-type="standard"
data-shape="rectangular"
data-theme="outline"
data-text="signin_with"
data-size="large"
data-logo_alignment="left"
></div>
On Chrome (and the other non-ITP browsers) both buttons work properly and I receive the ID token (JWT) that contains a claim nonce with the nonce that I specified when rendering the page.
On Safari (ITP) with "Prevent cross-site tracking" the regular button produces a id token that has the nonce. But if I login using the One Tap (upgraded One Tap UX on ITP browsers) I get a ID token but that JWT does not contain any nonce claim.
Is there anything I could do to get the nonce to work also for the "upgraded One Tap UX on ITP browsers"?

Related

Google One Tap Javascript API/HTML API does not return nonce in JWT in Safari

When Google One Tap is implemented using Javascript API/HTML API including nonce, the returned JWT is missing nonce for Safari browser. Chrome and Fireforx returns the nonce as expected.
Please refer the code used.
const initializeGSI = () => {
google.accounts.id.initialize({
client_id: '132-xxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com',
cancel_on_tap_outside: false,
nonce: '7342364',
callback: onOneTapSignedIn
});
Browser Version
Safari Version 16.1 (18614.2.9.1.12)
Steps
Integrate Google One Tap using Javascript API/HTML API using a nonce.
Sign in via Google One Tap in Safari
Check retuned JWT
Using "itp_support" did not make any change on this.
This behaviour remains same for both Javascript API and HTML API.
When "Prevent cross-site tracking" is disabled at Safari, the nonce returns and works as expected. Safari has this default setting. Any workaround available other than changing the Safari's default behavior?

problem with Google identity sign-in with redirect (server-side)

I've been trying to update Google sign-in button on my website from old javascript method to new identity library, it works fine when I use callback function but the redirect option (for server-side verification) doesn't send credentials in POST request:
<html>
<body>
<script src="https://accounts.google.com/gsi/client" async defer></script>
<div id="g_id_onload"
data-client_id="my client id"
data-ux_mode="redirect"
data-login_uri="http://localhost:3001/api/google-auth">
</div>
<div class="g_id_signin" data-type="standard"></div>
</body>
</html>
In POST request it sends 'g_csrf_token' cookie, but doesn't contain 'credential' or 'g_csrf_token' in request body or parameters as mentioned in the document here
https://developers.google.com/identity/gsi/web/reference/html-reference#server-side
I believe I've set OAuth 2.0 Client ID and Consent Screen correctly. Any help will be appreciated

Expo: WebBrowser.openAuthSessionAsync and related calls skip user input even when browser session expired

This is a summary of an issue I filed directly with expo (it ws closed but I have asked for it to be reopened):
This issue happens whether using AuthSession.startAsync,
AppAuth.authAsync or WebBrowser.openAuthSessionAsync on iOS in
local development and published release (expo managed). Haven't tried
on standalone build yet.
Steps to Reproduce
user presses 'sign in' button, (app calls one of the above methods to kick start authentication session with a Salesforce oauth provider)
user enters credentials successfully
app goes through oauth redirects and returns user to our app and we get our access token.
user presses 'sign out' button (app calls revoke endpoint for token, then calls server endpoint to delete any browser cookie sessions for given account reference)
app navigates to sign in screen
user presses 'sign in' again (app calls the same method from above to start the authentication session with Salesforce oauth provider again)
instead of opening the sign in page, the app redirects itself back with an access token as if the user had successfully entered their credentials, even though any cookies/session data the browser stores should be invalid and necessitate a sign in.
Expected Behaviour
steps 1 - 5 are all as expected. Step six should be
app redirects to Salesforce oauth provider sign in page, in unauthenticated state (ie no cookie or session data that was previously stored is still valid)
user is required to re-enter their credentials
oauth flow takes over and redirects the user into the app if the credentials were correct.
Actual Behavior
as per initial steps where the user is not even asked to enter their credentials (step 6):
instead of opening the sign in page, the app redirects itself back with an access token as if the user had successfully entered their credentials, even though any cookies/session data the browser stores should be invalid and necessitate a sign in.
Reproducible Demo
The code is in a private repo so I can't share details of it, but it's a very standard oauth flow, and seeing it's happening in all three of the method calls from the top suggests to me that it may be due to something in the WebBrowser.openAuthSessionAsync implementation. I have seen on the apple developer docs that SFAuthenticationSession has been deprecated in favour of ASWebAuthenticationSession. My understanding is that this (SFAuthenticationSession) is the browser used by expo's WebBrowser and the wrappers mentioned above (AppAuth and AuthSession) for the oauth interactions. I also see that it mentions it's for a one-time login, which perhaps explains why it would hold onto any session data and jump to the conclusion of re-authenticating without directly seeking credentials from the user, but it seems unhelpful to store a cookie without validating it, which is what appears to be the end result.
Notes
Essentially this is making it impossible for a user to sign out of our app, because the system browser, that we don't have control over, is keeping track of their authentication despite the session value no longer being valid against the server.
I've seen other people looking to find ways to clear cookies from the system browser, which may be what this issue relates to, though it doesn't appear to be possible to access the auth session's browser cookies in any way. This comment on a GitHub issue is exactly what I'm experiencing and need to find a solution to.
I would like users to be able to sign out, and then when they sign back in again they should have to enter their credentials again. Does anyone have any thoughts as to how this might be possible?
On iOS, it's now possible to pass in the following config to WebBrowser.openAuthSessionAsync to essentially treat it as incognito and ensure it doesn't retain any cookies. The effect is that the user will have to re-authenticate each time (even if there session is still active). I'm not aware of a similar approach for Android, however.
Code
const browserOptions = {
preferEphemeralSession: true
}
result = await WebBrowser.openAuthSessionAsync(authUrl, redirect, browserOptions)

Google plus sign in, whats the best way to refresh the session?

For a web application that doesn't reload the page with in 3600 seconds, whats the best way to keep the session alive with google plus?
If I use the html sign in button, is there a javascript call to refresh the session?
Do I need to refresh the token, but does that update the session?
Would it be best to call the server and refresh the token, but then I need to update the client cookie?
Should I reload the page, this would suck b/c its an application that shouldn't do that?
Can I ask the javascript to sign in again, but I get a popup blocker?
How do I deal with the 3600 token expiring in a web application that doesn't refresh the page?
<span id="signinButton">
<span class="g-signin" data-callback="signinCallback"
data-clientid="xxxxxx.apps.googleusercontent.com"
data-cookiepolicy="single_host_origin"
data-accesstype="offline"
data-approvalprompt="auto"
data-theme="dark"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.login
https://www.googleapis.com/auth/plus.me
https://www.googleapis.com/auth/userinfo.email
email">
</span>
</span>
You can use the gapi.auth.authorize call of the JS Client library (which will be loaded with the Sign-in JS script), providing the same parameters you did in the Sign-in Button, and using 'immediate': true. Since the user already authenticated before, this will refresh the token automatically (if necessary).

CSRF with Twilio

I am trying to get Twilio to work with my express/node.js installation. Twilio is making an incoming connection to my server, when it gets a text message. Then I am replying to this with a SMS response.
This works the first time. Then the second time, my server blocks Twilio because it says that it was a forged request.
Is there a proper way to get around this?
You should disable CSRF for that URL. See this question on how to do that: Disable csrf validation for some requests on Express
CSRF is a vulnerability that only pertains to requests that require session information in the form of a cookie (which is why CSRF is also sometimes called "session riding"). In short, CSRF is when a malicious site owner can use a <form> tag on a page they control to post a form to your site, causing an authenticated request to be sent to your server without the user's knowing. For instance, let's say Facebook has a /delete_user.php which deletes the current authenticated user. A CSRF attack on that URL will be in the form (no pun intended) of a <form action="http://facebook.com/delete_user.php"> tag on the malicious site owner's site, which gets submitted without the user's knowledge. A non-CSRF-safe implementation of /delete_user.php will see the user's auth cookie and delete the user -- much to the user's dismay.
Anyway, long story short, your Twilio handler does not require a user's browser cookie, and thus is not subject to CSRF attacks. Just disable CSRF checks for the Twilio callback URLs.