spring oauth2 authorize flow in single page app - spring

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.

Related

Acceptable OAuth Flow for a decoupled frontend/Backend Architecture?

I have a NextJS frontend and Golang backend architecture with an authentication system using JWTs and an internal user/password database. I'm adding OAuth sign-in in addition to the JWT system, but all API calls will still be maintained using JWTs. I have a working prototype that uses the following OAuth flow:
User is directed to a NextJS page that displays various login options as buttons.
When a provider is chosen, the user is redirected to the backend at /auth/provider where they are then redirected to the provider with all required keys and callback links.
User logs in at the provider and the redirect is triggered to /auth/provider/callback.
The backend server retrieves the user data from the callback and connects the user email to the internal user data for generating a JWT.
The backend returns a page that stores the JWT in local storage and redirects to a NextJS page.
The NextJS page can then use the stored JWT to make API calls.
An additional step could be to exchange the JWT for a new, non-stored JWT or session cookie if the JWT is used twice (potential XSS attempt) and the new JWT is invalidated.
The above method works, but requires a locally stored JWT. Is this a concern, and is it possible to complete the final steps without the need for a locally stored JWT.
Does this flow make sense or am i going about it all wrong? Would swapping to PKCE be overkill?
For the current prototype I'm using the github.com/markbates/goth example code running as the golang backend and a basic NEXTjs server
In effect you have a form of backend for frontend there. It is worth browsing OAuth for browser based apps a little similar to section 6.2 of the above doc.
One option might be to host the backend at a URL like https://api.example.com, then make it write cookies for the Next.js app, hosted at a URL like https://www.example.com.
In this way the backend and frontend parts of the OAuth flow are decoupled, and you also avoid locally stored JWTs. Note the same domain prerequisite, needed for the cookie to be considered first-party, and therefore avoid being dropped by browsers later.

OAuth2 Provider with custom authentication

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)

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

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?

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.

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