Different browser behavoiur with claims when page is refreshed - cross-browser

We have an MVC/AngularJS system with a Web API back-end that uses Azure ACS and AAD to authenticate our users. The authentication works well, and when the user first authenticates the claims from ACS are passed in in the token.
We override the ClaimsPrincipal Authenticate method and verify that this user is a user of our system and add role claims here too.
After this the user is directed to the home page and the next step of the process requires the user to select an item from a list (e.g. their current location).
This selection determines how certain settings are applied in the web application. When the user makes this selection we make an ajax call to the Web Api back-end and here we add another three claims to the token, reflecting the user's selection.
Now if I refresh the page after this selection has been made the whole process starts again, but different browsers behave differently.
For Chrome and Opera the 'ClaimsPrincipal Authenticate' is called again, the roles are added again and the user need to make the selection again to add the three claims (i.e. when the page is refreshed a copy of the token before our code modified it is used).
For Firefox and IE the refresh passes in a token with all the claims that we added programatically, so it didn't revert the token to the initial state.
The latter behaviour is what I would have expected and what I would prefer. Is there any documentation on this, and for Chrome and Opera is there a way to ensure the current token is used when the page is refreshed?

Related

Playwright - "Verify it's you" message only for chromium, while trying to login to Google

I'm writing a Playwright test that starts with a Google Auth0 login. After I fill my test user and password in the UI (google login), in Firefox and Webkit the authentication passes successfully, while, on Chromium, I'm getting the Verify it's you message (with a "send sms" message).
The account does not have 2 steps authentication.
When it happened locally, I opened the browser in headful mode, and after few clicks (which I assume "told" the browser that I'm a real user) the problem disappeared (I can now run my tests in headless mode locally). But, it still happens on CI (GitHub)
I run the test with chromium flags: --disable-dev-shm-usage and --disable-web-security.
I couldn't find any data about it anywhere...
When Google determines that a user is logging in from an unknown device or a new location, they may prompt the user with an additional login challenge.
The login challenge that the user receives depends on the information that associated with the account.
Does the prompt say "Enter a phone number to get a text message" or something else like "This device isn't recognized..."
If the former I believe you can circumvent this extra prompt by having a phone number linked to the Google account in question. If the latter I believe the prompt is once per user per device.
My understanding it is basically Google trying to get a valid phone number for the account (to prevent spam etc).
-- Edit
The only other thing I can think of is that you can temporarily turn off the verify-it's-you challenge, for 10 mins, but only if the account is a member of a Google Workspace or Cloud Identity service. I am not sure this is possible for an unmanaged account - or how useful it would be. The other issue is that for "free services" Google doesn't really offer any kind of support.
Anyhow, you might try "Temporarily turn off login challenges for a user" -
https://support.google.com/a/answer/12077697
There is also so good information on this verify-it's-you challenge here.
https://workspaceupdates.googleblog.com/2018/04/more-secure-sign-in-chrome.html
It has some notes on disabling the challenge per organization via response headers, but again this is for an organization and managed accounts.
If you wish to disable the new screen for your organization, you can
use the X-GoogApps-AllowedDomains HTTP header to identify specific
domains whose users can access Google services. Users in those domains
won’t see this additional screen, as we assume those accounts are
trusted by your users. This header can be set in Chrome via the
AllowedDomainsForApps group policy.

why is my web browser not sending cookies when I click a link, but it sends them just fine when I type in the url

I am creating a web application in Golang/HTML. I am implementing registration, sessions, email verification, and login.
My code works, however I have noticed some strange browser behavior. When the user registers for the first time, my application will send them an email containing a link with a unique nonce (number used once) in the url. This is to ensure that the user is able to receive email from us at that address and "verify their email", as is standard practice on many web applications.
Please click the following link to verify your account: http://localhost:8080/verify-email/55c17d2c
I noticed that when I receive this email, if I click on the link in the email, the browser will open the link in a new tab as expected, however, it will not send any cookies on requests associated with that tab.
But when I copy and paste the link into a new tab manually and press enter, it sends the cookies just fine. What gives? is this some sort of undocumented security feature? What should I do about this?
I used https://github.com/six-ddc/httpflow to capture a log of the HTTP requests and responses going between my web browser and my server application. I have two separate logs, one of them captured a registration flow where i clicked the link, and the other one captured a registration flow where i copy and pasted the link into a new tab.
Log where link in email was clicked: https://paste.cyberia.club/~forest/2f3fce7dcc71fc095341eeaefb33f20883c79886
Log where link was copy and pasted from email into url bar: https://paste.cyberia.club/~forest/0623f76cfee339e91d2213dd8f4c7710c6fa2797
Please note that I tried this on firefox and google chrome, I also tried it with a real domain and https certificate, got the same behavior in all browsers and setups.
Here are my constraints:
I want the application to work fine with javascript disabled, however, I'm open to javascript-based solutions if they are simple, secure, and make the site more enjoyable to use. For example, I am using a javascript that hashes passwords client side before sending to the server for login. But if javascript is disabled, the raw password will be sent.
I don't want the user to have to log in again after they click the link to verify their email address.
I don't want the link in the email address to represent a "free pass" into the user's account. I want to require the user to be already logged in (or somehow otherwise authenticated) before they can verify their email address. For example, if someone steals that email and clicks that link before the intended user does, I don't want the email thief to be able to take over the account.
OOPS I just figured this out, I wanted Lax SameSite policy on my cookies:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#SameSite_attribute
It takes three possible values: Strict, Lax, and None. With Strict, the cookie is sent only to the same site as the one that originated it; Lax is similar, except that cookies are sent when the user navigates to the cookie's origin site, for example, by following a link from an external site;

Need refresh token without using consent screen in G Suite

We are using G Suite API with our Micro service for document editing, and we have a different data center and also different db. now once user comes to my application and trying to open document first time then google give consent screen based on that i can get refresh token and access token and i store into one data center.
But problem is that if user comes from another instance which use different data center with different db and user trying to open document with old credentials then google doesn't give any consent screen so i am not getting user's refresh token.
1) So is there any way to get refresh token without using consent screen?
2) Is there any way to identify if user comes from different sub domain then i need to provide consent screen for that?
It might be possible to use the prompt=consent option to force a re-prompt for auth, even though the user has already authorized your app.
See https://developers.google.com/identity/protocols/OAuth2WebServer#creatingclient
You can identify the user's domain using the hd parameter [1] and you can request a refresh token without the consent screen after the domain admin has configured domain wide delegation by installing your application from the GSuite Marketplace [2].
[1] https://developers.google.com/identity/protocols/OpenIDConnect#hd-param
[2] https://support.google.com/a/answer/172482?hl=en
When you request an OAuth Flow (access_type=offline`), a Refresh Token is returned to your application. This only happens once (obtaining a Refresh Token). Your application is expected to save the Refresh Token for future needs.
In your use case, one of your systems completed the authentication and the user has moved to a different system. You will need to reauthenticate with prompt=consent, access_type=offline. You will not get another Refresh Token without reauthenticating.
I spent a lot of time on this issue last November. Here is a link which has lots of details on this problem.
Any application can only have one valid refresh token for a user. You can request for a new refresh token using the prompt=true&access_type=offline on the request as said by #John. But every time the previous one will become invalid.
Based on you comments on the other answers, I'm assuming creating a new micro service that returns the token to the one being used is not a possibility (that would be my recommendation)
You asked "to identify if user comes from different sub domain"...
If those applications are for end users of gmail.com accounts, you can treat them as different applications and configure different projects on the developer console.
It will be a bit of a pain when enabling new APIs, I would recommend doing that from a script that replicates to all application needed.
If your end users are from companies using GSuite, you can have your app installed as domain-wide application (either manually or from GSuite Marketplace). In that case you can use just client side authentication to get an id_token, send the token to the server and use a service account to impersonate the user in any given service without worrying about any token from them.

How do I persist login state for a user between my website and my chrome extension

I built a Chrome Extension, where a login form is displayed as a side bar using content scripts injection. I do not want the user to see this login form if the user is already logged in on the website and vice versa if the user logs in on the Chrome Extension and then visits the website, user should automatically log in.
I am returning tokens from the backend when a user successfully logs in.
My question is, what is the best way to store these tokens so both the content scripts in my extension and the website have access to the token to check to see if the user is already logged in.
As far as I understand I have localStorage, ChromeStorage but I do not know if they are shared between the tabs of the browser and the extension.
Any direction is highly appreciated.
Thank you.
If you're returning tokens, a reasonable way to do it would be to inject a content script into pages that match the callback URL containing the token, extract it and save into chrome.storage. It is shared between the content script and all other extension contexts.
Do note: chrome.storage is not exactly secure: it's not encrypted on disk, and can be snooped upon with Dev Tools. Then again, the token is normally stored in the cookie store, which can be likewise examined even without access to the (slightly) more secure password storage.
Perhaps the only more secure way to keep the token in the extension is chrome.identity API, but then you have to login separately, defeating your goal.

oauth for html5 enabled devices

I'm building a webapp specifically for iOS and Android devices which requires user to sign in with their Facebook or Twitter accounts. I have it setup so that initially they're redirected to the appropriate login page and upon successful completion my provided calllback url is triggered.
Because I want to implement a single sign on, I will be storing on the user's device the access token that I received so they can easily access the webapp without having to sign in again next time.
My question is this: is it better to store it as an html4 cookie from the server side? Or is it better to insert it as a hidden input in the home page and have javascript on the client grab it and store it with the new local/sessionStorage? And if the latter, which type of storage would be better for this type of data that I would like to save?