I'm trying to understand and implement a client credentials flow between our new REST server and our existing client app. I've setup spring-security OAuth2 like this. From my understanding so far, my server should now support the following request:
$ curl -X -v -d 'client_id=the_client&client_secret=secret&grant_type=client_credentials' -X POST "http://localhost:9090/oauth/token"
but I get
InsufficientAuthenticationException: There is no client authentication
caused by the Principal being null here (spring-security code) :
#FrameworkEndpoint
#RequestMapping(value = "/oauth/token")
public class TokenEndpoint extends AbstractEndpoint {
#RequestMapping
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal,
#RequestParam("grant_type") String grantType, #RequestParam Map<String, String> parameters) {
if (!(principal instanceof Authentication)) {
throw new InsufficientAuthenticationException(
So it seems, I need to authenticate against the server first. But that's not what I want to do. I want two of my servers to talk to each other using a shared secret. The OAuth provider server should provide an access token to the (trusted) client server on request so that the client server can then use that token to access all REST resources on the server. This should protect the REST resources from external access.
Later I want to provide selected resources to a third party and eventually implement some finer grained security for the server-to-server communication as well. But for now I need to protect the REST server from external access.
Looks like I might have some misunderstandings about the whole client credentials flow or the application of spring-security right there so any clarification would be greatly appreciated.
You are not authenticating your client to the Authorization server.
You need to do something like this:
curl --user the_client:secret --data "grant_type=client_credentials" http://localhost:9090/oauth/token
This is authenticating the client to the authorization server and then specifying grant_type and other parameters. This will return an access token of type 'bearer' with scope determined by the oauth client details. Once you have the token, you can access your protected resources by setting the Authorization header:
curl -H "Authorization: Bearer <accessToken>" <resourceUrl>
Related
I have a spring-boot application and I am using keycloak to authenticate users. I am planning to make an endpoint in my application that waits a username and a password, it logs-in to keycloak and if the username/password is valid ask for an access token and give it back to the user.
How can I make this log-in to keycloak?
As I see I need to have a public client to make my keycloak use username/password, but this does not contain any resource_id so I need an access_token from a confidential client.
Should I ask for an access_token from the public client, and if the response code is 200 (so the login is successful) then send another request to the confidential client to get back an access_token that is actually working?
Thanks in advance.
I am planning to make an endpoint in my application what waits a
username and a password, it logs into the keycloak and if the
username/password is valid ask for an access token and give it back to
the user.
If we assume that
the Spring App is configured correctly;
the Keycloak client that the users will be authenticating against uses Authorization Code Flow (i.e., Standard flow Enabled on Keycloak), or even better Authorization code flow with PCKE
then when a user logins into your app, the user gets redirected to Keycloak for authentication. The user is redirected (probably) back to your app (if the authentication is successful), and your app receives, among others, an access token. That access token can then be used to perform actions on behalf of the authenticated user.
As I see I need to have a public client to make my keycloak use
username/password, but this does not contain any resource_id so I need
an access_token from a confidential client.
From the RFC 6749 OAuth 2.0 specification one can read:
confidential
Clients capable of maintaining the confidentiality of their
credentials (e.g., client implemented on a secure server with
restricted access to the client credentials), or capable of secure
client authentication using other means.
public
Clients incapable of maintaining the confidentiality of their
credentials (e.g., clients executing on the device used by the
resource owner, such as an installed native application or a web
browser-based application), and incapable of secure client
Since you are neither using a pure web browser application nor a mobile phone but instead a spring-boot application with a secure backend, you should use a confidential client.
You are mixing up concepts if you mean that you want to use "Resource Owner Password Credentials Grant" (i.e., Direct Access Grants Enabled in Keycloak). You can still used with your application without having to use a confidential client. With a public client the request for a token from Keycloak looks like:
POST -d "client_id=<client_id>"
-d "username=<username>"
-d "password=user_password"
-d "grant_type=password"
<KEYCLOAK_HOST>/auth/realms/<REALM_NAME>/protocol/openid-connect/token>
with a confidential client:
POST -d "client_id=<client_id>"
-d "client_secret=<client_secret>"
-d "username=<username>"
-d "password=user_password"
-d "grant_type=password"
<KEYCLOAK_HOST>/auth/realms/<REALM_NAME>/protocol/openid-connect/token>
you got the extra field -d "client_secret=<client_secret>".
Bear in mind, however, that:
The resource owner password credentials grant type is suitable in
cases where the resource owner has a trust relationship with the
client, such as the device operating system or a highly privileged
application. The authorization server should take special care when
enabling this grant type and only allow it when other flows are not
viable.
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.
I have read and implemented my own Auth server following this tutorial from Spring. There are multiple SSO providers - Facebook, Github and a custom auth server. In this tutorial, the auth server contains the handling of other SSO providers.
I have a separate resource server that links to my auth server using the following properties:
security.oauth2.resource.userInfoUri=http://localhost:9000/user
I am able to get the token from my auth server using a cUrl command:
curl acme:acmesecret#localhost:9000/oauth/token -d grant_type=password -d username=user -d password=...
{"access_token":"aa49e025-c4fe-4892-86af-15af2e6b72a2","token_type":"bearer","refresh_token":"97a9f978-7aad-4af7-9329-78ff2ce9962d","expires_in":43199,"scope":"read write"}
But what I fail to understand is how can I use the other SSO providers to get such token as well from the auth server? The resource server should not care how did I get the token and whether I am authenticated using Facebook or my custom auth server. It should simply ask the auth server what is the Principal (logged user) and then decide which resources to show him, right?
I don't have any UI and this will be backed for a mobile application so I need to udnerstand how to handle the authentication using REST reqeusts.
If I understand your question correctly,
how can I use the other SSO providers to get such token as well from
the auth server?
This custom Auth server is abstracting out your interaction with FB or Github and issuing you it's own token. The token that your custom Auth server spitting out is not an FB or Github token, it's a token generated by your custom Auth server (After authenticating with FB/Github token).
Then why do we need FB/github?
How else your custom Auth server can identify a person, It sure can use user Id and Password; consider 'login with FB' as another nice option it gives to the user.
How to add other SSO providers like digitalocean in addition to FB and github?
Just do the same as we did for FB and Github (register a client id with digital ocean and then in auth server application, Add client Id and secret in the properties/yaml file etc)
The resource server should not care how did I get the token and
whether I am authenticated using Facebook or my custom auth server. It
should simply ask the auth server what is the Principal (logged user)
and then decide which resources to show him, right?
Yes, your understanding is correct.
Edit (To answer question asked in the comment)
But lets say I log in with Facebook through my Auth server. Where do I
find the token that I can use with the Resource server? Let's say I
have a RestClient and want to make a request to obtain some resource
belonging to a user which went through the Facebook auth process via
my auth server. Where do I find the token to use?
If that's a requirement, I think you can use this example instead; you may not need a custom auth server as such. Whole point of having custom auth server is abstracting out the interaction with FB or github.
Or
If you still want to go with custom auth server direction, then expose an endpoint from Auth server (which will get you the resources you need from FB) and then make use of that from your resource server.
While using REST authentication with Keycloak, my id_token is null (server side). To connect to the application, I am using the following URI:http://localhost:port/auth/realms/{name}/protocol/openid-connect/token provided in the documentation (with the appropriate form params grant_type, username, password,... see here). In response (client side) I can retrieve the access_token and id_token. Then, I am using the "Bearer" authorization in the HTTP header to discuss with the server. While using my custom client, the id_token is null in the server side. Can someone explain me why?
(Just to be clear, all is working well by using the keycloak authentication page)
It seems that the id_token is only used while using the GUI authentication interface. To bypass my problem, I added my custom metadata to the access_token, then replaced all the reference to the id_token (on server side) to the access_token. By doing this, the application is fully compatible with the OAuth2 protocol.
I've a have a public RESTful API that is used for user authentication for a web application that accepts the user id and password in clear text (see below). The username is passed in the url path as a path parameter and the password is a query string parameter. The HTTP GET comes from another web application on the server side (http client request), is this API secure? I was under the impression that the URL can not be seen if the request is going from server to server. My main fear is that someone could use something like firebug and see the traffic and get the userid and password.
REST end point:
HTTP GET https://host:80/user/joebob?password=pass123
Someone most definitely could see the username and password with a simple network sniffer. If you are POSTing the request, why are the parameters in the URL? They should be in the body like a normal POST, then at least the SSL protection kicks in and people can't sniff them. Another option would be for you to look at HTTP Basic Auth.