Oauth
Since Camel 4.12
The camel-oauth module comes with Processors that can be added to a route on the client and resource owner side. These processors intercept the message flow and perform the necessary authentication steps against an Identity Provider (IdP) in some specs it also called Authorization Server. Our primary choice of IdP is Keycloak
The idea is that a "Resource Owner" can give a "User Agent" access to some protected resources without sharing credentials directly with the agent.
For example, Alice has an account with Spotify and now wishes to use a cool service from Acme which compiles a daily playlist according based on Alice’s preferences. Instead of giving Acme her Spotify credentials (i.e. username/password) directly, Acme can obtain an access token from an Identity Provider that encodes the scope and duration for Acme to access Alice’s Spotify account. Alice can revoke access any time - Acme never sees more information than what Alice has granted and is necessary to perform the wanted service.
Maven users will need to add the following dependency to their pom.xml for this component:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-oauth</artifactId>
<version>x.x.x</version>
<!-- use the same version as your Camel core version -->
</dependency> Authentication/Authorization Flow Types
OIDC Authorization Code Flow
The Authorization Code Flow returns an Authorization Code to the Client, which can then exchange it for an ID Token and an Access Token directly. The Authorization Code flow is suitable for Clients that can securely maintain a Client Secret between themselves and the Authorization Server.
This code flow relies on user interaction with a browser based application. It is not suitable for fully automated authorization for example in the case of REST based service interaction.
For details see the OIDC 1.0 spec.
Configuration Properties
| Name | Description |
|---|---|
| The base URL to the identity provider (e.g. https://oauth.localtest.me/kc/realms/camel) |
| Valid URI pattern a browser can redirect to after a successful login (e.g. http://127.0.0.1:8080/auth). Must be registered with the identity provider. |
| The client identifier registered with the identity provider. |
| The client secret provided by the identity provider. |
| (Optional) Valid URI pattern a browser can redirect to after a successful logout. Can be registered with the identity provider. |
Client Credentials Grant
A client can request an access token using only the client id and secret shared with the identity provider.
This flow is suitable for fully automated authorization, for example in the case of REST based service interaction.
For details see the OAuth 2.0 spec.
Configuration Properties
| Name | Description |
|---|---|
| The base URL to the identity provider (e.g. https://oauth.localtest.me/kc/realms/camel) |
| The client identifier registered with the identity provider. |
| The client secret provided by the identity provider. |
OAuth SPI for Component Integration
The camel-oauth module provides an SPI (OAuthClientAuthenticationFactory) that allows other Camel components to use OAuth Client Credentials authentication without a compile-time dependency on camel-oauth. Components discover the factory at runtime via Camel’s FactoryFinder mechanism. If camel-oauth is not on the classpath, a clear error message instructs the user to add it.
Components that support this integration include: camel-openai, camel-huggingface, camel-docling and camel-ibm-watsonx-ai. Each of these components exposes an oauthProfile parameter.
Named Profiles (Multiple Identity Providers)
Named profiles allow configuring multiple identity providers in a single application. Each profile is identified by a name and has its own set of properties.
Configuration Properties
Properties are resolved from camel.oauth.<profileName>.*:
| Name | Required | Description |
|---|---|---|
| Yes | The client identifier registered with the identity provider. |
| Yes | The client secret provided by the identity provider. |
| Yes | The OAuth 2.0 token endpoint URL. |
| No | The OAuth 2.0 scope to request. |
| No | Whether to cache tokens. Default: |
| No | Default token expiry if |
| No | Safety margin subtracted from token expiry to refresh early. Default: |
Example: Multiple Identity Providers
# Keycloak for backend services
camel.oauth.keycloak.client-id=backend-client
camel.oauth.keycloak.client-secret=backend-secret
camel.oauth.keycloak.token-endpoint=https://keycloak.example.com/realms/main/protocol/openid-connect/token
# Azure AD for OpenAI
camel.oauth.azure.client-id=openai-client
camel.oauth.azure.client-secret=openai-secret
camel.oauth.azure.token-endpoint=https://login.microsoftonline.com/tenant/oauth2/v2.0/token
camel.oauth.azure.scope=https://cognitiveservices.azure.com/.default Components reference a profile by name via the oauthProfile parameter:
- route:
from:
uri: "direct:start"
steps:
- to:
uri: "openai:chat-completion"
parameters:
model: "gpt-4"
oauthProfile: "azure" Using the SPI Programmatically
Components and custom code can use the OAuthHelper utility from camel-support:
import org.apache.camel.support.OAuthHelper;
// Resolve a token from a named profile
String token = OAuthHelper.resolveOAuthToken(camelContext, "keycloak"); For advanced use cases, the OAuthClientAuthenticationFactory can be used directly with an explicit OAuthClientConfig:
import org.apache.camel.spi.OAuthClientAuthenticationFactory;
import org.apache.camel.spi.OAuthClientConfig;
import org.apache.camel.support.ResolverHelper;
OAuthClientAuthenticationFactory factory = ResolverHelper.resolveMandatoryService(
context, OAuthClientAuthenticationFactory.FACTORY,
OAuthClientAuthenticationFactory.class, "camel-oauth");
String token = factory.resolveToken(
new OAuthClientConfig()
.setClientId("my-client")
.setClientSecret("my-secret")
.setTokenEndpoint("https://idp.example.com/token")); Trusted Certificates
Naturally, we want all communication between camel and the identity provider to be secured at the transport layer (TLS). For this, the Camel service need’s to trust the identity provider’s certificate.
# Fetch the certificate from the IdP endpoint
openssl s_client -connect oauth.localtest.me:443 | openssl x509 > cluster.crt
# Import certificate to Java Keystore (i.e. trust the certificate)
sudo keytool -import -alias keycloak -file cluster.crt -keystore $JAVA_HOME/lib/security/cacerts -storepass changeit
# Trust this cert on macOS
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain cluster.crt
# Trust this cert on Linux
sudo cp cluster.crt /etc/pki/ca-trust/source/anchors/ && sudo update-ca-trust OAuth for Kafka
For Kafka we can use strimzi-kafka-oauth directly, for example like this …
Supported Runtimes
Camel OAuth is supported in all Camel Runtimes
-
camel-main
-
spring-boot
-
quarkus
Specifically, it provides an abstraction for the various http-platforms that are native to these runtimes.
Supported Cluster Environments
Camel applications requiring OAuth authentication are likely part of a larger more complex system architecture, which also likely are part of some larger Kubernetes cluster deployment. In our examples we support these Kubernetes environments …
-
Local Cluster (e.g. DockerDesktop Kubernetes)
-
Remote K3S Cluster
-
Red Hat OpenShift
As part of this project we provide a set of Helm charts that install the required infrastructure components for the respective cluster environment. For details, have a look at the dedicated readme.
Keycloak is already configured in such a way that below examples should run without further ado.
Camel OAuth Examples
There is a comprehensive set of camel-oauth examples as part of camel-cloud-examples. You’ll find camel-jbang kubernetes examples for every OAuth flow, for every runtime, on every supported cluster.
For example in the following makefile:
k8s-fetch-cert:
@mkdir -p tls
@echo -n | openssl s_client -connect oauth.localtest.me:443 | openssl x509 > tls/cluster.crt
k8s-export: k8s-fetch-cert
@$(CAMEL_CMD) kubernetes export platform-http-files/* tls/* \
--dep=org.apache.camel:camel-oauth:4.19.0-SNAPSHOT \
--gav=examples:platform-http-oauth:1.0.0 \
--property=camel.oauth.base-uri=https://oauth.localtest.me/kc/realms/camel \
--property=camel.oauth.redirect-uri=http://127.0.0.1:8080/auth \
--property=camel.oauth.logout.redirect-uri=http://127.0.0.1:8080/ \
--property=camel.oauth.client-id=camel-client \
--property=camel.oauth.client-secret=camel-client-secret \
--property=ssl.truststore.certificates=tls/cluster.crt \
--ignore-loading-error=true \
--image-builder=docker \
--image-push=false \
--trait container.image-pull-policy=IfNotPresent \
--runtime=camel-main