auth0.js checkSession() returns a login_required error after logging in with login() from an embedded page - session

I am trying to add ‘keep me logged in’ functionality to my auth0 v9.3.0 authentication flow in my SPA. I have an embedded page at app.domain.io/login where the user enters their credentials. When they hit the sign-in button, the app calls the login() method from auth.js, passing in the username and password. If they checked the box, a permission cookie is set to true.
When the user launches the page later, after the token expires, a router guard calls auth0.js’s checkSession() method to get a new token. At this point, checkSession returns a login_required error even after the user logged in with auth0.js’s login() method. If I instead call the authorize() method and have the user log in on the hosted page, checkSession succeeds and does not return a login_required error.

Why does calling the login() method from the embedded page not fulfill the login_required requirement that authorize() fulfills? I want to get this working without ever redirecting the user to the hosted auth0 page.
Update: 03/28/18
I am currently using auth0 v9.3.0.
Instead of calling the login() method, I am now using axios to make a request to the co/authenticate endpoint. This succeeds and returns a login_ticket, co_id, and co_verifier.
When I call authorize() from auth0.js and pass in the login_ticket as mentioned in the documentation (https://raw.githubusercontent.com/jaredhanson/draft-openid-connect-cross-origin-authentication/master/Draft-1.0.txt), I get a ‘No verifier returned from client’ error. I have the co_verifier, but I’m not sure what to do with it.

Here is a fully working sample to follow (SPA using plain JavaScript). The sample illustrates both embedded login and universal login (auth0 hosted login page) approaches.
If you have a codebase on Github and don't mind sharing, then I can take a look for you. Please also update your question to indicate version of auth0.js you are using (or put in comment section below). Do you know (you can check using web browser developer tools) whether you are using co/authenticate endpoint when authenticating using auth0.js embedded login? If so, then you would have a Single Sign On session. However, if you are using oauth/token endpoint then this would not create a single sign on session. the checkSession() function calls authorize?prompt=none under the covers, which detects whether a SSO session is present as part of the authentication process.
Finally, and just for the record, the strong recommendation is to use Auth0 Hosted Login Page (Universal Login). It is a superior approach from security standpoint, and offers other benefits like easy opt-in to services like MFA out of the box. Finally, you could also enable Custom Domains so that your website and the Auth0 Hosted Login Page share the same URL base origin (domain) - end users of your site would not recognise they have been redirected to Auth0 for the authentication. So it is pretty seamless from a UX perspective too.

This issue was solved by calling auth.crossOriginAuthentication.login() instead of auth.client.login(). auth.crossOriginAuthentication.login() goes through co/authenticate, auth.client.login() goes through oauth/token.

Related

How do you apply the JWT from msTeamsSilent demo to the ClaimsIndentity and ensure it uses the msTeamsSilent when encountering Authorize tag?

The example can be found here:
https://github.com/vitNickW/TeamsAppMultiAuth/tree/main/src/TestTeamsAuthSSO
msTeamsSilent is being used to launch a popup to allow Microsoft Identity authentication to function within an IFrame (the default redirect will not work). However, the code doesn't seem to do anything with the actual JWT that is returned and it is not updating the ClaimsIdentity.
How do you:
...update the ClaimsIdentity so that an MVC project will recognize that the authentication was completed?
...get the [Authorize] tag to call the popup routine instead of doing the redirect if the user is not already authenticated?
...get the authorization to persist from one page to another?
We are OK if you only can provide a fix using .NET Code instead of .NET Framework.
We are OK if a different authenticating method is used (e.g., MSAL instead of ADAL). The important part is that we need a Popup instead of a Redirect authentication and have it recognized correctly by the MVC application.

asp.net core 3.1 Identity - redirecting to login after SignInAsync() when referrer is Stripe

We have an issue with a asp.net core 3.1 MVC application. The application is using the built in asp.net Identity feature. The application is working well for existing users. If you hit any [Authorized] route, you are redirected to the login page as expected.
However, rather than have a registration process in our app, for new users, we onboard them via Stripe Checkout. Upon successful payment, stripe redirects to a specific route in our application /conversion/success/{sessionid} where sessionid is the Stripe session. This action is marked as [AllowAnonymous].
We then pull the necessary customer details from Stripe, create a user in our repository via UserManager<T>. We then call SignInManager<T>.SignInAsync() to sign in the new user, before redirecting the new user to the [Authorized] home page.
This process works perfectly when running locally on our test machines. Also, when running on our production server (Azure App Service) it also works perfectly when we hit the route manually through the browser.
However, when we actually run the process through Stripe, complete a payment and let Stripe redirect the customer, we get a strange behaviour.
The conversion route is hit, the user record is created, the sign in process completes but upon redirection to home page, the authentication middleware takes over, says it's not authenticated and redirects to the login page.
Just to compound matters further, if you then simply type in the home page route in the browser, the user is in fact logged in exactly as expected and the application works perfectly.
Using Fiddler to intercept the calls and look at headers, etc. we can't see why there would be a different behaviour when coming from Stripe as opposed to typing directly. We've even tried redirecting from a different website to our registration process and that works as expected too.
Any idea why we are seeing this behaviour?
---- Update ---
If, rather than redirect to home page at the end of the onboarding process, we simply show a simple View with an anchor link to home page, the user can then go to home page as expected.
Is it possible that you're rendering the page before authentication has been completed? Since UserManager uses a cookie to establish the user's session, authentication needs to complete before any response headers or body is set so that the Set-Cookie header can be sent in the response.
Based on what you described it sounds like the user is hitting the homepage after the redirect without having the authentication cookie. Where I'd start debugging this is by using your web inspector with "Preserve log" turned on and going through the Stripe Checkout process. Then, inspect the headers sent to the browser when you land on the redirect page & make sure the authentication cookie is set.
Between requests to Stripe and SignInAsync it seems possible that there might be a missing await, so the redirect is happening before the authentication context is updated. Hard to say more without seeing your code!

How to handle social login? - example flow

I have more conteptual question, how exactly should I handle social login in my project.
The use case is that I would like to allow user to login with Facebook, and keep on my backend information about this user (email, firstname, lastname)
I have some proposal Flow, but I'm not sure if it's a proper approach.
Let's say that I have application architecture as above. Now I would like to explain step-by-step full success flow.
Client (Vue application) make a call to AuthProvider (Facebook)
AuthProvider returns access_token
Client after reciving access_token make a call to backend endpoint like /fb_profile with access_token and userID (?)
Backend make a call to AuthProvider to check if given by client access_token is valid or not.
AuthProvider returns information about user. Backend after getting information about user, save it to database and generate new JWT token
Backend returns generated token to user
Now my question is - Is this good approach? Or should i handle it in other way? Like keep more logic to backend part? Instead of make a call to Facebook from Client, maybe should I make a call to backend, and backend make a call to Facebook?
You seem to be on right track. There could me many ways to do the same thing, here is the way which is working for me using vue/laravel/passport/socialite/github.
Trigger redirect in controller from frontend,
Provider(here github app) is triggered in browser with its url using client id/app name saved in back end config/env. Fill out your login details
It will redirect as created in provider and configured in backend-> show it on frontend, in my case its
http://localhost:8080/authorize/github/callback
From frontend now trigger callback in controller, it will check if user details already exist and will insert if its first time user as per logic. Then it will send back access_token to frontend which can be used in frontend for all the operations
DB
The above will be the sequence of the request flow ( same as yours ).
This would be the standard practice we used to integrate with Facebook. In this case, I strictly advise you to use the JavaScript SDK for Facebook.
Refer below link in case if you run into the following issue:
Vuejs component wait for facebook sdk to load

Web API (under IIS) Windows Authentication with Bearer Token

It's so strange that this simple solution is not yet implemented or is it that I can't Google it ;p) (I'm trying from last 5 days).
My requirements:
Call from Angular App (withCredentials = true) on a URL to see if it is windows user (challenge NTLM). (I may configure this based on what URL user accessing it). If it's a valid Windows user and I find them in DB, I return the Bearer Token.
If Above call returns Unauthorised (401), I show login form to user in my AngularJS (1.6) client. User provides non-windows username and password and when user click Login, from angular service go to another URL (for getting Bearer Token - standard OWIN stuff).
** In any case above, I store Bearer Token in my client for any further API interaction.
I'm not using ASP.NET identity but I have my own DAL to verify user from DB.
I'm going to have my own custom Authorise (inherited) attribute (which will check for Bearer Token only).
I don't want users to enter Windows login on my form and to authenticate them from Active Directory.
I Don't want windows users to click on any separate button to login. (They should just login seamless - with prompt from browser asking them windows login)
I've seen hundreds of posts but nowhere I could see exactly what need. Either the mixed authentication needs to be Cookie based or separate MVC implementation. (Lot's of confusion)
Already referred:
https://techblog.dorogin.com/mixed-windows-forms-authentication-for-ajax-single-page-application-e4aaaac0424a
https://techblog.dorogin.com/mixed-windows-forms-authentication-for-ajax-single-page-application-e4aaaac0424a
https://github.com/MohammadYounes/OWIN-MixedAuth
Don't know if this may help: (but again with cookie) https://github.com/pysco68/Pysco68.Owin.Authentication.Ntlm
Can someone please help?
I may have to give up on this by tomorrow evening :-(

In GWT: how to bookmark a page and be able to be redirected to it after authentication?

I have implemented an OAuth2 authentication mechanism in my GWT app. The OAuth2 server is based on Spring framework 3.x (using its Spring security OAuth2 implementation).
I am using the OAuth2 "Authorization code flow" to get the user authenticated (though implicit flow may have been a better choice in our case). So at first, the user is redirected to the OAuth2 server authentication page, he enters his credentials and if he is successfully authenticated, he is redirected back to a url with an oauth code. He will then make a second call to get an access token from the OAuth2 server.
Now, the issue is, we would like the user to be able to bookmark a page in the application and directly access it. If he has already authenticated then he would have direct access to it (no more auth involved). Otherwise, he would have to go into the OAuth2 authentication flow but in the end, should be redirected back to the bookmarked page he intended to access at the beginning.
How can I store this page url and get redirected to it after the user successfully authenticates ?
any help would be appreciated. Thanks!
EDITED
The initial url redirection is done via javascript's document.location.href
The way to maintain the original URI in an OAuth 2.0 Authorization Grant flow is to pass it in the state parameter so that the redirection endpoint can use it, after it exchange the authorization code for an access token, to redirect the user back to that URI.
FYI, this is exactly what Google suggests in the examples in their OAuth 2.0 documentation, e.g. https://developers.google.com/accounts/docs/OAuth2Login
Original answer:
The problem is using the hash part of the URL for the place, which is not sent to the server and thus cannot be used in the redirection to the OAuth2 server authentication page.
You have 2 (maybe 3) solutions:
stop using the hash for the place and switch to HTML5 History; either through gwt-pushstate at the History level, or a custom PlaceHistoryHandler.Historian if you use the Places API. That limits your audience though: http://caniuse.com/history
stop using an HTTP redirect, and instead use JavaScript so you can put the hash in the OAuth2 redirect_uri. So instead of redirecting, send an error page with the appropriate scripts bits.
some browsers append the hash to the URL after a redirection, so your OAuth2 server might be able to pick it (in JavaScript) and append it to the redirect_uri. That might depend on the HTTP status code used for redirecting (from experience, it works with a 301, but you don't want a 301 here). Needs testing.
You can do this using GWT activities and places.

Resources