How to secure custom REST API endpoints in IntegrationManager using Basic Auth (partition credentials) or OAuth2 (JWT / opaque tokens).
Overview
When an external system calls IM's REST API (the Camel routes exposed via integration.rest.*), IM must verify who the caller is. Two authentication modes are supported:
|
Mode |
|
How it works |
|---|---|---|
|
Basic Auth (default) |
|
Caller sends |
|
OAuth2 |
|
Caller sends a Bearer token issued by their own Identity Provider. IM validates the token locally (JWT) or via introspection (opaque). |
Both modes enforce the same authorization rules defined by integration.rest.endpoints.secured, integration.rest.endpoints.roles, and integration.rest.doc.* properties.
Where to Configure
All authentication properties go into your instance's config/application.properties file. REST endpoints are defined as Camel routes in the routes/ directory.
/
├── config/
│ └── application.properties # ← auth properties go here
├── routes/
│ └── my-rest-api.xml # ← your REST endpoint routes
├── connections/
│ └── pricefx.json # ← Pricefx connection (used by Basic Auth)
└── ...
For details on the IM project structure, see Project Structure.
Quick Start
Basic Auth (default):
integration.rest.enabled=true
# auth-mode defaults to "basic"
integration.rest.auth-mode=basic
integration.rest.endpoints.path=/rest
integration.rest.endpoints.secured=true
# endpoints.roles defaults to ADMIN
integration.rest.endpoints.roles=ADMIN
OAuth2 with JWT:
integration.rest.enabled=true
integration.rest.endpoints.path=/rest
integration.rest.endpoints.secured=true
# clear the default (ADMIN) — accept any authenticated user
integration.rest.endpoints.roles=
integration.rest.auth-mode=oauth2
# token-type defaults to "jwt"
integration.rest.oauth2.token-type=jwt
integration.rest.oauth2.jwt.issuer-uri=https://{your-idp-domain}/...
That's it — any valid token from your IdP will be accepted. To restrict access to specific roles/scopes, see Authorization Rules below.
Note: The default value for
endpoints.rolesisADMIN(used by Basic Auth). When switching to OAuth2, you must either clear it (accept any authenticated user) or set it to a role/scope from your IdP along withroles-claim.
Authentication Modes
1. Basic Auth (Partition Credentials)
This is the default mode. Your external system sends Pricefx partition credentials with every request. IM validates the credentials against the Pricefx partition API using the connection defined in connections/pricefx.json (or via integration.pfx.* properties).
What your external system sends:
POST https://{im-host}/rest/myEndpoint
Authorization: Basic <base64-encoded username:password>
Content-Type: application/json
The username can be in two formats:
-
username(e.g.admin) — authenticates against the default partition from thepricefxconnection -
partition/username(e.g.company/admin) — authenticates against the specified partition (overrides the connection)
Minimal configuration:
integration.rest.enabled=true
integration.rest.endpoints.path=/rest
integration.rest.endpoints.secured=true
# endpoints.roles defaults to ADMIN — caller must have ADMIN role on the partition
With custom role:
integration.rest.enabled=true
integration.rest.endpoints.path=/rest
integration.rest.endpoints.secured=true
integration.rest.endpoints.roles=DATAINTEGRATION
2. OAuth2 (JWT)
Your external system obtains a token from your Identity Provider (Azure AD, Okta, Keycloak, etc.) and sends it to IM as a Bearer token. IM validates the token locally using your IdP's public keys — no per-request calls to the IdP.
What your external system sends:
POST https://{im-host}/rest/myEndpoint
Authorization: Bearer eyJhbGciOiJSUzI1NiJ9...
Content-Type: application/json
What IM needs from you:
-
The IdP's issuer URI or JWKS endpoint URL
Minimal configuration
integration.rest.enabled=true
integration.rest.endpoints.path=/rest
integration.rest.endpoints.secured=true
integration.rest.endpoints.roles=
integration.rest.auth-mode=oauth2
integration.rest.oauth2.token-type=jwt
integration.rest.oauth2.jwt.issuer-uri=https://{your-idp-domain}/...
Or with a direct JWKS endpoint (preferred — avoids OIDC discovery):
integration.rest.enabled=true
integration.rest.endpoints.path=/rest
integration.rest.endpoints.secured=true
integration.rest.endpoints.roles=
integration.rest.auth-mode=oauth2
integration.rest.oauth2.token-type=jwt
integration.rest.oauth2.jwt.jwk-set-uri=https://{your-idp-domain}/.well-known/jwks.json
Property details
|
Property |
Required |
Description |
|---|---|---|
|
|
Yes |
Set to |
|
|
Yes (or |
Your IdP's issuer URL. IM discovers the signing keys automatically. |
|
|
Yes (or |
Direct URL to your IdP's JWKS (signing keys) endpoint. Preferred over |
Note: If both
jwk-set-uriandissuer-uriare set,jwk-set-uritakes precedence for key retrieval. Theissuer-uriis still used for issuer validation.
Examples by Identity Provider
Azure AD:
integration.rest.auth-mode=oauth2
integration.rest.oauth2.token-type=jwt
integration.rest.oauth2.jwt.jwk-set-uri=https://login.microsoftonline.com/{tenant-id}/discovery/v2.0/keys
integration.rest.oauth2.jwt.issuer-uri=https://login.microsoftonline.com/{tenant-id}/v2.0
Okta:
integration.rest.auth-mode=oauth2
integration.rest.oauth2.token-type=jwt
integration.rest.oauth2.jwt.issuer-uri=https://{your-domain}.okta.com/oauth2/default
Keycloak:
integration.rest.auth-mode=oauth2
integration.rest.oauth2.token-type=jwt
integration.rest.oauth2.jwt.jwk-set-uri=https://{host}/realms/{realm}/protocol/openid-connect/certs
integration.rest.oauth2.jwt.issuer-uri=https://{host}/realms/{realm}
3. OAuth2 (Opaque Token / Introspection)
Instead of validating the token locally, IM forwards it to your IdP's introspection endpoint on every request. The IdP confirms whether the token is valid and returns its scopes.
This mode is useful for testing or when your IdP doesn't expose a JWKS endpoint.
Important — Token format restriction: The Bearer token must conform to the RFC 6750
b64tokenformat. Only the following characters are allowed:A-Z a-z 0-9 - . _ ~ + /and=for padding. Tokens containing other characters (e.g.!,#,@) will be rejected with a 401 Unauthorized error and the messageBearer token is malformed. This affects providers like Salesforce, whose opaque tokens use the formatorgId!sessionId. Salesforce tokens are not compatible with this mode.
Minimal configuration:
integration.rest.enabled=true
integration.rest.endpoints.path=/rest
integration.rest.endpoints.secured=true
integration.rest.endpoints.roles=
integration.rest.auth-mode=oauth2
integration.rest.oauth2.token-type=opaque
integration.rest.oauth2.opaque.introspection-uri=https://{your-idp}/oauth2/introspect
integration.rest.oauth2.opaque.client-id=im-client
integration.rest.oauth2.opaque.client-secret={{oauth2.client.secret}}
|
Property |
Required |
Description |
|---|---|---|
|
|
Yes |
Set to |
|
|
Yes |
Your IdP's token introspection endpoint URL |
|
|
Yes |
Client ID for authenticating to the introspection endpoint |
|
|
Yes |
Client secret. Use an encrypted property placeholder. |
Authorization Rules
By default, REST endpoints require the ADMIN role (configured via integration.rest.endpoints.roles=ADMIN). To change this, configure audience validation and/or role/scope requirements below.
Audience validation (JWT only)
Ensures the token was issued for your IM instance, not for a different application:
integration.rest.oauth2.jwt.audience=api://my-im-app-id
Restricting by role/scope
For OAuth2 JWT — set the JWT claim containing roles and the required value:
integration.rest.oauth2.jwt.roles-claim=scp
integration.rest.endpoints.roles=im.call
The roles-claim property tells IM where to find roles in the JWT token. It depends on your IdP:
|
IdP |
|
Example role |
|---|---|---|
|
Azure AD |
|
|
|
Okta (scopes) |
|
|
|
Okta (groups) |
|
|
|
Keycloak |
|
|
For OAuth2 opaque tokens — roles come from the scope field in the introspection response automatically. No roles-claim needed:
integration.rest.endpoints.roles=im.call
For Basic Auth — roles come from the Pricefx user's role assignments automatically:
integration.rest.endpoints.roles=DATAINTEGRATION
Authorization logic
# REST endpoints — require authentication and specific role
integration.rest.endpoints.secured=true
integration.rest.endpoints.roles=DATAINTEGRATION
# API documentation — public access
integration.rest.doc.secured=false
|
|
|
Who can access |
|---|---|---|
|
|
(ignored) |
Everyone — no authentication required |
|
|
(empty) |
Any authenticated user — no specific role required |
|
|
|
Only users with at least one of the listed roles |
Role matching is case-insensitive.
endpoints.roles=im.callmatches a token scope ofim.call,IM.CALL, orIm.Call.
Choosing Between OAuth2 and Basic Auth
|
|
Basic Auth |
OAuth2 (JWT) |
|---|---|---|
|
Setup |
Works out of the box |
Requires IdP configuration |
|
Security |
Password in every request (over HTTPS) |
Signed token — no password in transit |
|
Performance |
First call requires Pricefx API calls (then cached) |
Token validated locally — no external calls |
|
Token expiry |
No automatic expiry |
Tokens expire automatically |
|
Access management |
Via Pricefx user accounts |
Via your own Identity Provider |
Recommendation: Use OAuth2 JWT when you have an Identity Provider. Use Basic Auth for simple setups.
Troubleshooting
|
Problem |
Possible cause |
Solution |
|---|---|---|
|
IM fails to start with |
OAuth2 JWT mode enabled but no JWKS/issuer URI configured |
Set |
|
IM fails to start with |
|
Either clear |
|
IM fails to start with |
Opaque mode enabled but introspection properties missing |
Set |
|
401 Unauthorized — |
Token contains characters outside the RFC 6750 |
Opaque tokens must only contain |
|
401 Unauthorized with OAuth2 |
Token is invalid, expired, or from wrong issuer |
Check that |
|
401 Unauthorized with OAuth2 + audience |
Token's |
Verify |
|
401 Unauthorized with Basic Auth |
Wrong username/password or partition unreachable |
Check credentials; verify |
|
403 Forbidden with OAuth2 |
Token is valid but missing the required role/scope |
Check |
|
403 Forbidden with Basic Auth |
User authenticated but doesn't have the required role |
Assign the required role to the user in the Pricefx partition |
|
REST endpoints return 401 but should be public |
|
Set |
|
OAuth2 chain not active (Basic Auth prompt instead) |
|
Set |
Tip: Enable
logging.level.org.springframework.security=DEBUGinapplication.propertiesto see detailed authentication/authorization decisions in the logs.
Complete Property Reference
|
Property |
Default |
Description |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
(empty) |
IdP issuer URI |
|
|
(empty) |
Direct JWKS endpoint URL |
|
|
(empty) |
Expected audience value |
|
|
(empty) |
JWT claim with roles/scopes (required when |
|
|
(empty) |
Introspection endpoint URL |
|
|
(empty) |
Introspection client ID |
|
|
(empty) |
Introspection client secret |
|
|
|
Base path for REST endpoints (e.g. |
|
|
|
Require authentication for REST endpoints |
|
|
|
Required roles (comma-separated). Clear for OAuth2 or set to your IdP's role/scope. |
|
|
|
Require authentication for API docs |
|
|
(empty) |
Required roles for API docs |