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?
Related
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/
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.
I am trying to implement a OAuth2 Provider, that authenticates users with a custom login.
For understanding I looked at the Spring Boot OAuth2 Tutorial.
I don't quite get, how I can implement my own Authentication meachnism to work with the OAuth2 SSO from my Server.
I want to add custom authentication mechanisms (like "user has to answer a question for authentication" or "user has to enter id and click button for authentication") instead of the Facebook and Github examples.
I read about implementing my own AuthenticationProvider, but I am stuck how to combine all the puzzle parts.
Let's go one step at a time. OAuth is only authz provider so not talk about authentication. Now for your usecase specifically, if you want user to be authenticated then OAuth authz code based flow makes sense (You can even go for implicit flow, check rfc 6749). Now how will this work for you. I am picking up the implicit flow for simplicity, Authz flow is just extension of it where end client gets a temporary code which it exchanges with Identity Server later to get the access token. Here are the steps:
Client App hits the /authorization uri with data as per rfc 6749
After validating the submitted data, server forwards user to Login page (or other page for authentication). After authentication, cookie is set in the browser or data is stored in server to mark a user as authenticated.
After authentication server redirects user to user consent page (You can even skip this if needed depending on need, But OAuth 2 spec contains this) where user specifies which all permissions (scopes) are allowed, here user can allow either allow or deny.
if user allows then these permissions are submitted to server and then server stores the data and redirects the user to client URI with access token in # fragement of client redirect URI (callback URI submitted during actual request)
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?
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.