OAuth2 Implicit flow vs 'Traditional' session based auth for small SPA - session

Some background:
I am writing a small SPA that will use a back end that I have also written. The JS and the back end API are on the same server.
i.e. SPA will load from foo.com, back end is at foo.com/api
In the past I have always used Spring Security with simple form based login. After logging in the user will get a session cookie. Pretty standard stuff.
For this app I looked into OAuth2 implicit flow. My understanding is the User would load my page, then from the SPA I would direct the user to the authorization endpoint so my app could get a token. The user would be redirected from the authorization endpoint to a login form. After the user authenticated with the form.. they would be redirected back to the authorization endpoint to get the token and possibly grant access to the JS client. After that the user would be redirected to a URL specified by the client, with the new access token as a URL fragment.
I have this working and its all great. The part I don't quite get is this:
When the user is redirected to the login form and they authenticate a session is created on the server that has to at least last long enough for the user to be redirected to the authorization endpoint to get the token. At that point they already have an authenticated session on my server, why not just stop there and use traditional cookie and session based logins?

Related

Laravel Passport and PKCE authentication - Do you need a session for the user to login?

I setup a PKCE authentication system for an API using Laravel Passport.
At the moment this API is used by a SPA.
The authentication flow is the following :
User clicks on "login" on the SPA
User is redirected to the API /oauth/authorize endpoint (with all the pkce required parameters)
Now, that API endpoint requires the user to be authenticated. So the login page is shown (its a php Laravel served view)
The user logs in, clicks on authorize, and is redirected to the callback url of the SPA, which will then send a request to obtain the JWT token.
From this point all communication from the SPA and the API will use the JWT token only.
Everything works. Except I now have a few doubts.
Is it correct for the login on step 3 to be session based ? To set that up I simply used Laravel UI, which provides an already setup login functionality, which is session based.
If I visit the API login page again, by its own url, I am actually session logged in (which is normal). Of couse if I logout from that page (it has also a logout button), I can still use the SPA normally, as I still have my JWT token which is used by Passport.
To solve the logout problem I had to implement a 'double' logout, one that clears the JWT from local storage for the SPA, and one to logout the user from the session login of the Laravel api (in case that was still active at the time).
All this seems a little off, should I refactor the login function of Laravel UI to not start a session (if that is even possible) ? Or maybe log the user out in some way(how ?) after the redirect to the SPA callback url ?
Thanks

Add a SSO flow to Laravel Passport

We are trying to implement a SSO solution using Laravel Passport. There is already a question about this topic but I think this one is more about the nitty-gritty.
Our requirements are:
A Laravel Passport service running on passport.com
Some first-party sites on various domains: foo.com, bar.com
Users can log in to foo.com and bar.com by typing their access details directly (Password Grant)
If a user logs in to foo.com and then they visit bar.com they should be automatically logged in
Based on my understanding of Oauth2, the system should work like the following:
Initial login flow:
The user types in their details on foo.com
foo.com makes a request to passport.com/oauth/token using a Password Grant and retrives an Access Token and a Refresh Token. Additionally, a SSO Token is generated and returned.
foo.com redirects the user to passport.com/sso/passthrough , passing the SSO Token and a return URL as query parameters.
passport.com saves the token as a cookie and then redirects to the return URL.
The user returns on foo.com and they can use the site
Note that the redirect to passport.com MUST take place, as otherwise browsers like Safari and Chrome in incognito will consider passport.com to be a third-party domain and the cookie will be blocked.
SSO flow:
The user visits bar.com
bar.com makes an AJAX request to passport.com/oauth/authorize using a SSO Grant and the redirect URI bar.com/sso/return
On passport.com, the SSO Grant looks for the SSO Token in the cookies and if the token is found, an authorization code is produced and sent bar.com/sso/return as a redirect. Because AJAX requests don't handle redirects, control passes directly to bar.com.
bar.com exchanges the authorization code for an access token and returns a successful AJAX response
bar.com receives the AJAX response and triggers a page refresh since the user is now logged in
For clarity, the SSO Token, SSO Grant, passport.com/sso/passthrough and bar.com/sso/return routes are not part of Laravel Passport; they are new concepts that we are implementing here.
The questions here are:
This flow looks to me like it should work. Am I missing anything?
Does this introduce any vulnerability into the Oauth2 flow? The Access Token and Refresh Token are never displayed to the client, but the SSO Token is. If an attacker steals it, I'm guessing they could potentially impersonate the user.
The Oauth2 protocol and Laravel Passport are stateless. By adding a cookie we are adding state. Is this a necessary evil or can it be done in a different way?
Should the SSO Token be saved to the cookie directly or should there be a different kind of token or authorization code there?
Any tips for implementing the SSO Grant and SSO Token?

Is it possible to logout from wso2is from my backend?

Are there another ways of doing logout without redirecting my Frontend to oidc/logout page (it works fine,but isn't it insecure sending idToken and my IDP url to frontend),i have separate front and back end. Like in Keycloak which invalidates session by sending refreshToken? If not,what is a right way of doing logout in my application?
We are sending the ID_Token in POST request directly to the IS Server thus it should not have any security concerns. Using ID_Token as id_token_hint while doing a logout is coming from OIDC specification[1]. This will prevent attackers from logging out users from their accounts because only the real RP can present the valid ID Token.
If you want an alternate way to logout you can make use of session management API[2]. But it is recommended to use the logout endpoint.
[1]https://openid.net/specs/openid-connect-session-1_0.html#RPLogout
[2]https://is.docs.wso2.com/en/5.9.0/develop/session-mgt-rest-api/

spring oauth2 authorize flow in single page app

I am implementing an oauth2 authorization server for providing access to our apis.
Our application is a single page application, with the a jwt token in the authentication header to provide access.
We want to setup an oauth2 Authorization Code flow like,
User is on external site and wants to get access to our apis
External site redirects to our site/spa with oauth2 params, client_id etc.
SPA checks authentication, users needs to login to continue
User sees page for confirming access
User confirms access, code is returned and redirected to external site
External site does backchannel call to obtain token from code
My problem is in 4 and 5, in standard Spring setup this is provided by
org.springframework.security.oauth2.provider.endpoint.AuthorizationEndpoint,
on /oauth/authorize GET oauth params are stored in the session and the confirmation page is shown, and on post of that the code is returned in the redirect.
But I cannot find any guidance/examples on how to do this with a page hosted in a SPA.
You have to be authenticated in this endpoint and I cannot really use the top level page that /oauth/authorized provides because we use header based authentication on rest api calls only, all our top level calls are unauthenticated.
Is there some obvious way to make this work?
I think I do not want to put my authentication token in a cookie.
I was thinking of just then creating a controller that sort of does what the AuthorizationEndpoint does and returning a redirect to the redirect in Javascript. But I am not sure if I would be breaking some other security requirement.

Issue token to logged in user via spring

I have a Spring (3.2) based web app that a user can log into. The site will also provide an API secured via OAuth 2.0. My question then, is how do I go about generating a token for a logged in user?
The underlying idea here is that there will be a mobile app that opens up a web frame to the login page, which will eventually redirect to a url schema with an oauth token that the app will catch and then use for the api calls. Looking at the code for TokenEndpoint, I see that it defers token creation to a list of TokenGranter types. Should I be creating my own TokenGranter extended class, or am I looking at this all wrong?
I ended up writing a controller like this:
OAuthClientRequest request = OAuthClientRequest
.authorizationLocation(csOauthAuthorizeUrl)
.setClientId(csClientId)
.setRedirectURI(
UrlLocator.getBaseUrlBuilder().addSubpath(AUTH_CODE_HANDLER_URL).asUnEscapedString())
.setResponseType("code")
.buildQueryMessage();
UrlUtils.temporarilyRedirect(httpResponse, request.getLocationUri());
return null;
Then handling the code returned. My big problem here was that I had the /oauth/authorize endpoint set to use client credentials. Once I realized that tokens were being issued for the client ID instead of the user, it started to make sense.
So you want to use the Authorization Flow of OAuth. Spring has already support that, if you have configured the spring-security-oauth correctly, you just have to redirect the user/your mobile apps to /oauth/authorize?client_id=xxx&response_type=code this will redirect user to authorization page, if user has not login yet, it will redirect the user to login page then to the authorization page.
After the user completed the authorization process, it will redirect the user to an already registered redirect_url parameter with the authorization_code 'yourapp.com/callback?code=xxxx'.
Your application should exchange this authorization_code with the real token access to /oauth/token?grant_type=authorization_code&code=xxxx&client_id=xxxx&client_secret=xxxx
After that you will receive the token access that can be used to access the resource server.

Resources