I'm currently building a microservice backend with Spring Boot, Zuul as API Gateway and Keycloak as Authentication and Identity Provider.
For my frontend I'm currently using Angular as an SPA with the Authorization Code Grant.
The API Gateway should validate each request (if the user is authorized) via Keycloak before sending it to the microservice.
Each microservice ( ResourceServer) should be able to get the user information for the current request by using the introspection endpoint.
What would be the correct way to implement this, or is this even a bad design and I'm on the wrong way?
Typically, you have two options:
JWT given to client: The client (Angular SPA in your case) authenticates and receives the JWT. The JWT token can be verified by an party using the Keycloak public key. It also contains a lot of user information.
JWT given to back-end: The client is given the temporary authorization code grant. It is forwarded to a backend system, which exchange it for the JWT. The backend system will need to create a user session, store the JWT in the user session and use a session ID cookie (or a similar mechanism) to match the client to the session.
The proposed architecture is a mix of both worlds. Option 1 would be more natural.
Option 1: The client authenticates with Keycloak and gets the JWT. It then attaches the JWT to each request. Zuul can check that the JWT is signed by the trusted Keycloak instance and that it has not yet expired (without contacting Keycloak). The microservice can do the same. If more than the basic user information is needed, the microservice can contact Keycloak.
Option 2: I can't tell you if option 2 is possible with Zuul. Let's assume that it is. If so, the gateway would redirect unauthenticated requests to Keycloak. Once the client has received the authorization code grant, it is redirected to the API gateway. The API gateway then contacts Keycloak to exchange the code for the JWT and saves it in a session. The client is given a session ID. When a request is forwarded to the micro service, the JWT is added to the request. The client never sees the JWT.
These descriptions assume that you are using Open ID Connect, which is supported by Keycloak. If you use an OAuth 2 setup, most things still apply but a few details are more complicated, e.g. instead of the JWT containing all the information you get an opaque token that can only be validated against an introspection endpoint.
Related
I have a frontend and backend application (angular + spring boot). The frontend is served as static web content, then it sends the REST calls to the backend API on the same port.
Keycloak with OpenID protocol is used for users authentication and role management. Upon an request which requires authentication, the browser is redirected to Keycloak, user gives username and password then user roles are returned to the browser written into the access token.
Later the frontend sends this access token with every request, the backend checks the token signature against Keycloaks public key before fulfilling the request.
Currently it works fine with one public client in Keycloak. But I am required to switch to confidential client.
How is this even possible? My understanding is that confidential application requires the client secret in the token request, which can not be sent to the browser... because it is secret.
Can someone please explain?
You typically tend to move to the BFF-pattern to better secure your SPA applications so that you do not have to deal with tokens directly in the SPA application.
Do read more about the SPA pattern here:
The BFF Pattern (Backend for Frontend): An Introduction
This video is also a good intro to what you have to do:
alert‘OAuth 2 0’; // The impact of XSS on OAuth 2 0 in SPAs
I am trying to set up authentication server for spring boot application. I have multiple microservices application. Let say hospitals, patients, reports applications. I have each of microservices service application to be authenticated before allowing user to access the resources.
Can I know how can I have common authentication logic as a separate application. let say authentication application. I am planning to us (spring security with Auth 2.0 and JWT token).
For example:
When user tries access hospital dashboard page, we will check the user is authenticated
First we need to check whether user is authentication if not I need
to redirect to login service in authentication application.
Once user is logged in, then when he try to access dashboard we will
check the token is valid. If valid then allow user to access the
dashboard service.
Now user try to access patient details which is there in patient.war as a separate project, as the user already logged in we need to valid token, then we need to allow access to resources API what he is trying to access. If token is invalid then we need to redirect to login page.
Question:
I have gone through some example they have authentication server and resource server as separate application. i.e #EnableAuthenticationServer and #EnableResourceServer. But I have noted this got deprecated in latest spring boot version if I am right. Please correct me if I am wrong.
How can I have authentication functionality as common war file and let the other resource server access it before allowing the user to access the reset service API?
Which is the right way to build a microservice application?
I need some experts help to understand the best approach we need to implement authentication and authorization in latest spring boot version.
This is a relatively older question but I'll answer since it may help others.
For any microservices-based architecture, the api gateway is an important aspect and it should be there.
All your microservices will be hiding behind the gateway and any calls made to the downstream services (hospitals, patients etc) will go through the gateway.
This gives you multiple advantages.
You can add login (authentication) functionality in the gateway
You can put rate limiter to avoid DOS attacks
A single point of entry for the outside world so your clients don't neet to know the URL of each microservice
Now, the way it works is:
The client sends username/password or client_id/client_secret to the /login endpoint which is inside the gateway (for example GatewayController)
Gateway sends credentials to an "Auth-Service" which authenticates the user from a db or anywhere and creates a JWT (Oauth token)
Gateway returns the jwt back to the client
Client calls the, let's say, /patients endpoint through gateway with the jwt as header "Authorization" parameter
Gateway -> Auth-Service (To validate the token)
If invalid, 403 forbidden is sent. Otherwise, request is forwarded to the downstream service (in this case Patients-Service)
Patients-Service sends the jwt token to Auth-Service to get permissions from inside the token since we know that the token has already been validated.
Once the permissions list is received, the Patients-Service matches them with the permissions mentioned on each api (for example PatientsController)
If any permission matches, the response is served. If not, 403 forbidden is served.
To make it more clear, Auth-Service is called once when the call is for login(authentication). Auth-Service is called twice for all other api calls(validate + permissions).
I'm reading the article on how to secure my Spring Cloud Gateway with the token relay pattern.
https://spring.io/blog/2019/08/16/securing-services-with-spring-cloud-gateway
See https://static.spring.io/blog/bwilcock/20190801/demo.png
After a user requests a resource, the gateway redirects him to the login page of the identity provider to authenticate himself.
On success, the identity provider redirects you back to the original requested resource (the gateway), including the access-token provided by the identity provider.
So now the gateway is secured. Why does the resource-server has to validate the access-token again against the identity provider? Didn't the gateway just validate it?
Or didn't it, and the gateway is just there to relay the access-token to the resource-server so he can validate it?
Basically never trust the JWT.
Finally, the Resource Server needs to know where it can find the public keys to validate the authenticity of the access token which it has been given. The UAA provides an endpoint which both the Resource Server and the Gateway rely upon at runtime to do this check. The endpoint is configured in the application.yml for each application
The resource server can never be 100% sure that the access-token was created by the Identity-Provider, or even came from the gateway. So at least, you should make sure that the access-token was signed by the Identity-Provider by using the public key, exposed by a configured endpoint.
I'm writing a mobile app that communicates to a remote Java service via REST. I have protected my (SpringBoot) web service with https protection (due to the nature of the data, it needs to be secure) but my question is about which user/password I use to secure the https calls.
Should the username and password I use in the https header be a service account that the client (mobile app) and Java service knows or should it be the public user's username and password? The easiest option is just to use a service account but this means the mobile app will have those details built into it and distributed publically (albeit in compiled form).
Going the other way and using the user's username and password means I'll have to have the logon REST endpoint open and unsecure (which is fine I guess), but it just makes it slightly more fiddly.
Good question, and I would reckon you to use token based authentication and authorization scheme. Firstly you should have a login page where client logs in by providing username and password which is authenticated by calling some remote login service which maintains it's own user store or may use an existing one in your organization if any. Upon a successful authentication, the auth service should provide the client with a valid token, which then be refreshed time to time. The mobile or web client should pass in the token to the downstream microservices when a request is sent and this token should be sent inside the Authorization HTTP header.
Exposing the username and password while passing it around the network normally not considered as a good solution and that's where token becomes handy too. Token is the normal procedure that people use to secure rest endpoints. Yous rest endpoint should intercept each and every request comes at it, passes the token to the auth provider and verifies that. If the token is valid it will allow the request otherwise it should deny it.
Security is a pretty much larger topic and you have X.509 certificates other than tokens to encrypt the data sent across the wire over https and so forth. I suggest you to take a look at the spring security documentation since that will be a good starting point. Spring Security gives lots of hooks for developers which can be used out of the box with some sensible defaults. You can use JWT style tokens, Oauth tokens and spring security supports all these different forms too.
I have a web project that needs to pull some data from a hosted versionone instance. The versionone instance uses SAML authentication for single sign-on.
The single sign-on itself uses a username and pin+one-time password for authentication so it is nearly impossible to hard-code those values into the application.
Is there a way to handle this situation? Can I set something in the header of the request to bypass the single-signon process?
As of release 13.1, VersionOne supports OAuth2 for authentication against the API endpoints. Both the Webserver flow (where the hosted instance POSTs auth tokens to your waiting HTTP server) and the Out-of-band flow (where the hosted instance gives the user a code to copy/paste to the client) are supported.
That may be a better match for your requirements, as the SAML process is difficult to complete without a web browser and user present.
Once the OAuth2 credentials are obtained by the app, it can operate without user intervention. At any time, the user may revoke the app's permissions inside of VersionOne.
With OAuth2, the process is:
Register your app with VersionOne, thus creating a client secret
Configure the app with the client secret data from the registration
Have the app request a permission grant, which sends you to the VersionOne server.
Login to the server as the user you wish the app to act as, and accept the grant.
Copy the grant code back to the app if using the out-of-band flow.
The app contacts the VersionOne instance and exchanges the code for a persistent token.
The app can apply the token as an "Authorization: Bearer " HTTP header to achieve access to the VersionOne endpoint
If the token has expired and the request returns Unauthorized, the client may attempt to refresh the token and try again, without user intervention.
There is some documentation available on the VersionOne community site.
And a few (in-progress) examples in the VersionOne OAuth2 Examples repository
We also have a (beta) HTTP proxy that can run on your app's server, forwarding requests to the VersionOne instance after wrapping them with OAuth2 and SSL.