For redirect based OAuth 2.0 authorization code flow, a user agent like a web browser or mobile phone needs to be involved. In the light-oauth2 repository, we have provided a login-view single-page application based on React. In this section, we are going to walk through the application to show users the implementation details.
This single-page application should be hosted in the light-router instance as a virtual host along with a customer’s application. From the customer’s application, a login button will redirect to this login-view application URL with some query parameters like username, password, and client_id, etc.
The login-view is based on the redirect Authorization Code flow for Single Page Applications. We will provide another example of the mobile application later.
The original application will have a log in button or menu item. Once it is clicked, the browser will redirect to the login-view application, which is based on the React.
The login-view will accept username and password to invoke light-oauth2 code service.
Once authenticated, the code service will redirect to the /authorization?code=xxx to the browser.
The browser will invoke the above API, which is handled by StatelessAuthHandler in light-spa-4j. This handler is part of the middleware handler chain on the light-router.
The StatelessAuthHandler will use the code query parameter, client_id, client_secret saved on router server to get access token and refresh token from the light-oauth2 token service. The StatelessAuthHandler will save the access token, refresh token, csrf, userId, roles, and userType as cookies. The access token and refresh token are HttpOnly and Secure, so the browser application cannot access them. The handler also returns the redirectUri, denyUri, and scopes.
The login-view will use the response to display a consent page with a list of scopes and ask users to DENY or ACCEPT the grant.
If the DENY button is clicked, all the cookies will be removed, and the browser will be redirected to the denyUri. The entire flow is canceled.
If the ACCEPT button is clicked, the browser will be redirected to the redirectUri.
All subsequent calls to the light-router server from the original SPA will carry all the cookies to the request. The StatelessAuthHandler will capture the access token and refresh token and put the access token into the request header to invoke downstream APIs.
If the access token is expired or about to expire, The StatelessAuthHandler will renew a new token and put the new one into the request header.
To prevent CSRF(Cross-site request forgery), the original application must get the csrf cookies and put it into the request header for each request.
Above is a simplified flow without a lot of detail for easy to understand.
The source is generated with create-react-app, and the main logic is in the Login.js file. The component accepts query parameters from the redirect and uses the useState for the state, clientId, userType, and redirectUri.
It renders a login form that accepts username, password, and rememberMe. Once the submit button is clicked, the component will fetch the /oauth2/code to start the Authorization Code flow. If everything is OK, the light-oauth2 code service will redirect to the redirectUri registered in the client registration. In most of the cases, it will be your application domain with https protocol and the path /authorization.
There are two other components: ForgetPassword and ResetPassword. On the login page, there is a link to the forgot password page if you forget your password and want to reset it. You can input your email address on the page and click the submit button to have an email sent to you. In the email, there is a button that will direct you to the reset password page with a hidden token. You can enter your new password and password confirmation to reset your password on this page.
The login-view is calling the light-oauth2 code service for authentication and authorization. Internally, it uses the Java security GSSAPI to authenticate against the light-portal hybrid-query service. Due to the limitation of the API, there is no way that the error message can be passed to the authentication layer. If authentication is failed, a link will be displayed in the error message. By clicking the link, the hybrid-query loginUser service will be invoked directly, and you can see the error message on the browser.
Before using the SPA, you need to build the application and deployed as a virtual host on an instance of light-router. There are three different build options depending on where the light-oauth2 services are located.
If you deploy the light-oauth2 services on your own behind the light-router, then you can use the following command to build.