i want to reach a confidential client for my backend-system.
The SPA is an angular app. The backend a spring-boot application with different rest-endpoints which stores the objects in a postgres-db.
Actual my SPA got a login page which are connected to the oauth-server. My SPA is currently a public client (client-credentials are stored there). I want to reach a confidential client.
I attached a picture above. The SPA triggers the login. The backend now takes over the authentication, so that the backend is now the client. The backend receives the access token and stores it in a session db. The backend then issues an httponly cookie to the SPA so that the session is secured accordingly.
Is my architecture possible? Are there any examples somewhere? I have no experience in session management and want to programming as less as possible to avoid mistakes and vulnerabilities.
Thanks for help!
yes, you can setup a reverse proxy in the backend that will perform the OAuth 2.0 BFF task, for example see:
https://hanszandbelt.wordpress.com/2017/02/24/openid-connect-for-single-page-applications/
https://github.com/zmartzone/mod_auth_openidc/wiki/Single-Page-Applications
https://curity.io/blog/token-handler-the-single-page-applications-new-bff/
Related
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.
There is a several options on how to secure access to resource APIs from clients(web/mobile...), And in recent years, it was common to implement OIDC for SPAs in JS / TS, and this is no longer recommended.
The recommendation for SPA is to avoid storing tokens in the browser Or using service worker, And use a BFF insted of direct connect to Identity Server.
In this approach the BFF works as proxy of Identity Server and handle all oauth requests.
What is the best practice to implement this pattern with spring BFF, Or if there is another better approach.
Perhaps you're aware of this doc which explains the options. Assuming you are using an SPA and don't want the website option, there are 2 options, identical from a security viewpoint, and which you use is a matter of preference.
WEB BACKEND
The SPA sends OAuth and API requests to a web backend first, which forwards them and implements the OAuth client. The web backend uses a runtime that issues cookies.
Pros are an easier initial developer setup and fewer components to deploy. Cons are that all developers have to run the backend, and web deployment options are limited to those that can host the runtime.
REVERSE PROXY BACKEND
The SPA sends OAuth and API requests via a reverse proxy such as NGINX. OAuth requests are forwarded to a utility API. The web backend remains static content only.
Pros are that you can get rid of the cookie issuing runtime from a developer PC, and it is easier to do things like deploy web resources to a content delivery network. Cons are that the initial developer setup is harder and that there are more moving parts.
BEHAVIOR
In both cases the SPA uses URLs like this, for static content, oauth client and API routing responsibilities.
https://www.example.com
https://www.example.com/oauth-client
https://www.example.com/api
Within the oauth-client path, the SPA calls endpoints like this. The SPA OAuth code is very light:
POST /login/start
POST /login/end
IMPLEMENTATIONS
There are quite a few out there, including components you can plug in. Search for a term like BFF OAuth and do some reading. It is a journey though - cookies are complicated little things.
I have just added a tutorial on one of my repos for configuring spring-cloud-gateway as BFF between a browser application secured with sessions (Secure HttpOnly cookie) and an OAuth2 resource-server.
This sample uses Angular as UI framework, a thin wrapper of mine around spring-boot-starter-oauth2-resource-server, and Keycloak as authorization-server, but this are implementations details are all the work is done by the BFF.
I have a front end (angular) with login form, a back-end for that angular application as my OAuth client (spring dependency) then I have a third application that is the Authorization server and finally the forth is the ressources server.
So I want to know is there is any way to jump the redirect to /login from the authorization server?
I want to login the user with angular login page, then make a get with my OAuth client (spring) for the authorization code flow and then, since i'm not authenticated, instead of getting redirect, I want to get an error "401" and then send a post request with my OAuth client (spring) to the auth server again to login the user that have sent the data previously in angular login page.
Essentially I just wanted to login to my auth server with a custom page that exists in the front end application and let the backend build specially for that front, take over the flow.
You want seamless integration between login form and the rest of your Angular app? Share your CSS between Angular (public) client and authorization-server embedded (private) one, don't implement login in public client.
You might need to better grasp OAuth2 concepts.
Login, logout and user-registration are authorization-server business. Leave it there. Reasons are related to security and just being future-proof: what if you want to plug additional clients to your system (mobile apps for instance)? Are you going to implement login, logout and user-registration again and again? What if you have to introduce multi-factor authentication at some point? Would you break all clients at once?
Your "backend" (Spring REST API secured with OAuth2) is a resource-server, not a client. Make sure it is configured as so: depends on spring-boot-starter-oauth2-resource-server (directly or transitively). This is where the HTTP status for missing (or invalid) authorization is handled. The way to do it depends on your resource-server being a servlet or reactive app. The libs in the repo linked just before do what you want by default (401 instead of 302).
In your case, client is Angular app. I hope you use an OAuth2 client lib such as angular-auth-oidc-client to handle:
authorization-code flow (redirects to authorization-server, back from authorization-server with authorization-code and tokens retrieval with this authorization-code)
refresh-token flow (automatic access-token refreshing just before it expires)
requests authorization (add Bearer Authorization header with access-token on configured routes)
What my Angular apps do for login is just redirect users to authorization-server "authorization" end-point and then just wait for a redirect back to "post-login URL" with an authorization-code. How this code was obtained is none of their business (can be a login form, a "remember-me" cookie, some biometry, etc.).
Also, I have to admit that I don't use Spring's authorization-server. I prefer mature / feature-full solutions like Keycloak, Auth0, Okta, etc. which come with much more already implemented: multi-factor authentication, integration with LDAP, identity federation for "social" providers (Google, Facebook, Github, etc.), administration UI, ...
As ch4mp said, it's best to leave all the authentication and authorization logic and pages to the Spring Authorization Server, it's pretty easy to customize and configure all the user accessible pages (login, authorize, etc...) with Thymeleaf, you only have to bring in your CSS to unify the design.
There was a great demo in last year's Spring One which seems like something you'd like to achieve, you can find the code in this repo.
They used Spring Cloud Gateway as a means to run the Angular SPA in the flights-web app, configuring it as the OAuth client. Following this path you can route all calls to your backend API through the gateway's WebClient.
I am currently developing using spring security oauth2.
Currently, the frontend is SPA, and it is developed as react that operates with client side redering.
My rest api has the spring security starters libraries. But I don't know how to use oauth2 flow provided by spring.
So my question is: Can I use spring security as IAM to protect my web and api?
Does spring security have the known oauth2 grants and how use them ?
Implicit grant
Client Credentials Grant
Password grant
Don't use implicit grant
It is not recommended to use the implicit flow (and some servers prohibit this flow entirely) due to the inherent risks of returning access tokens in an HTTP redirect without any confirmation that it has been received by the client.
source: https://oauth.net/2/grant-types/implicit/
With implicit grant, access token is returned immediately without an extra authorization code exchange step. This extra step is usually performed in your backend.
Web > token > Api
SPA frontend and its Rest Api is a very common approach, used since simple startups until big companies. The flow summarized is:
Your users will start the web application.
As they were not signed in before, you web app will show them a login screen (a page provided by the authorization server).
After authenticating, a consent form is showed to the user.
After user consent, the authorization server will send you an authorization code.
The web app will exchange this code for a token.
After getting back this token, the web app store it in the client(browser) and send it as a header when apis needs to be consumed.
Your private rest apis must validate if token of the web app (header) is valid by sending it to one endpoint of the authorization server
If token is valid, your api rest is allowed to respond to the web client. For instance a json with products, employes, some update of customer order details, etc
For this flow to work, you will need:
web spa with a hint of backend. Backend is required because you cannot have a proper user session in static solutions like apache or nginx.
authentication and authorization server: Known as identity and access management (IAM) or some third app which provide you the basic oauth2 endpoints to manage a proper security for your apps.
your apis: foo-api , bar-api, baz-api, etc
spring security
In the minimal scenario in which:
you will have only one web + one rest api, and nothing more in the future (mobiles, iot, etc)
you don't have an authentication/authorization server
you have a mix of functional apis (employee, products, etc) and its security (spring-security) in just one artifact
you don't need user session in your web
you don't need a logout feature
Flow could be reduced to:
Your users will start the web application.
As they were not signed in before, you web app will show them a login screen (a page provided by spring-security).
After authenticating, a consent form is showed to the user.
After user consent, the authorization server will send you an authorization code.
The web app will exchange this code for a token. Since your api is using Spring security, the token generation is covered.
After getting back this token, the web app store it in the client(browser) and send it as a header when apis needs to be consumed.
Your private rest apis must validate if token of the web app (header) is valid by sending it to one endpoint of the authorization server I think the spring security chain filters handle this.
If token is valid, your api rest is allowed to respond to the web client. For instance a json with products, employes, some update of customer order details, etc
Here some samples of token generation and protected endpoints with spring security. I will try to upload a ready to use sample:
https://www.freecodecamp.org/news/how-to-setup-jwt-authorization-and-authentication-in-spring/
IAM
If you will have more applications and complex scenarios in the future, I advice you to choose some open-source iam like:
Glewlwyd,Keycloak,OAuth.io,ORY Hydra,SimpleLogin,SSQ signon,
Commercial services like:
Auth0,Curity Identity Server,FusionAuth,Okta,Red Hat Single Sign-On,cidaas.
Or try to develop a new one using pure spring-security
Lectures
Some recommended answers with more oauth2 details:
https://stackoverflow.com/a/62123945/3957754
https://stackoverflow.com/a/62049409/3957754
https://stackoverflow.com/a/57351168/3957754
https://stackoverflow.com/a/63093136/3957754
https://stackoverflow.com/a/54621986/3957754
https://stackoverflow.com/a/63211493/3957754
There are SNS application with 2 servers. Web backend server and REST API server.
The web server allows user login/logout with username/password, and show user information
The REST API server provides APIs like /topics, /comments, it should be stateless without session
The REST API will serve other web applications
There are some potential solutions, but neither is security.
Base Auth, the browser hold the username/password
Token with expiry timestamp, the problem is user could stay on the page until token expires
So, is there a way to protect the REST API when calling it from AJAX?
If I have understood your problem correctly I may suggest you use the Token solution. In order to maintain security you may generate new token on every request (& send it to client in response), which should be used to make next request, and disable token if it is once used or has expired.
Sorry, I meant to mention it as a comment, but I don't have enough reputation.