I've been following this guide on securing my JAX-RS API with Keycloak. I'm doing all the steps it provides, but sadly I can't get my authentication to work right. My requests always result in a 401 response. I hope some of you can help me with this problem.
I use docker-compose to run all containers.
docker-compose.yaml
version: '3'
services:
products:
image: maven:alpine
volumes:
- ./products/target/:/usr/src/products
command: java -jar /usr/src/products/products-0.0.1.jar
environment:
MYSQL_USER: mysql
MYSQL_PASS: mysql
ports:
- 8000:8080
networks:
- keycloak
keycloak:
image: jboss/keycloak
environment:
KEYCLOAK_USER: keycloak
KEYCLOAK_PASSWORD: keycloak
DB_VENDOR: postgres
DB_ADDR: keycloakDb
DB_USER: keycloak
DB_PASSWORD: password
ports:
- 8100:8080
depends_on:
- keycloakDb
networks:
- keycloak
keycloakDb:
image: postgres
volumes:
- ./volumes/keycloak/data:/var/lib/postgresql
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
networks:
- keycloak
networks:
keycloak:
driver: bridge
I use these settings to configure Kumuluz
config.yaml
kumuluzee:
security:
keycloak:
json: '{
"realm": "producerstore-realm",
"bearer-only": true,
"auth-server-url": "http://keycloak:8080/auth",
"ssl-required": "external",
"resource": "producerstore-api",
"confidential-port": 0
}'
Here is my JAX-RS application and a REST resource .
Api.java
@ApplicationPath("")
@DeclareRoles({"admin", "customer"})
public class Api extends Application {
}
ProductResource.java
@GET
@PermitAll
@Path("/products")
public Response getAll() {
try {
return Response.ok()
.entity(service.getAll())
.build();
} catch (Exception e) {
return internalServerError(e.getMessage());
}
}
@POST
@RolesAllowed({"admin"})
@Path("/products")
public Response createProduct(ProductDto productDto, @Context UriInfo uriInfo) {
try {
long createdId = service.add(productDto);
URI uri = uriInfo.getAbsolutePathBuilder()
.segment(Long.toString(createdId))
.build();
return Response.created(uri)
.build();
} catch (CreationException e) {
return internalServerError(e.getMessage());
}
}
I've also defined the admin and customer roles in Keycloak. Next I made a user and assigned these roles to them.
When I log in with that user I receive a correct JWT.
curl -X POST \
http://localhost:8100/auth/realms/producerstore-realm/protocol/openid-connect/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=password&client_id=producerstore-app&username=<username>&password=<password>'
which results in the following token
{
"access_token": "<very-long-token>",
"expires_in": 300,
"refresh_expires_in": 1800,
"refresh_token": "<another-very-long-token>",
"token_type": "bearer",
"not-before-policy": 0,
"session_state": "770908df-08fa-4935-8666-a58ae41447e7",
"scope": "profile email"
}
But when I try to request my resource, it always results in a 401.
curl -X GET \
http://localhost:8000/products \
-H 'Authorization: Bearer <very-long-token>'
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Error 401 Unauthorized</title>
</head>
<body>
<h2>HTTP ERROR 401</h2>
<p>Problem accessing /products. Reason:
<pre> Unauthorized</pre>
</p>
<hr>
<a href="http://eclipse.org/jetty">Powered by Jetty:// 9.4.15.v20190215</a>
<hr/>
</body>
</html>
I hope some of you can help me with this problem, if you need more information about something i'll happily provide it.
Thanks!