Skip to content

CAMEL-25022: camel-oauth - honor the JWT nbf claim when authenticating bearer tokens on the servlet backend - #26893

Merged
davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-25022-camel-oauth-nbf
Sep 28, 2026
Merged

davsclaus merged 2 commits into
apache:mainfrom
oscerd:fix/CAMEL-25022-camel-oauth-nbf

Conversation

@oscerd

@oscerd oscerd commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

What

When OAuthBearerTokenProcessor authenticates an access token through the Jakarta servlet backend
(ServletOAuth), UserProfile validated the JWS signature and the issuer, and UserProfile.expired()
evaluated exp, but the nbf (not before) claim was only copied into the profile attributes and never
evaluated. RFC 7519 section 4.1.5 specifies that a JWT must not be accepted for processing before its nbf
time. The Vert.x backend (through Vert.x User.expired(leeway)) and the OAuthTokenValidationFactory SPI
(JwtTokenValidator) already evaluate nbf.

Changes

  • UserProfile.verifyToken() — reject a token whose nbf is later than the current time plus the leeway
    configured in JWTOptions (getLeeway(), default 0, the same default as the Vert.x backend and the SPI
    clock-skew-seconds option). Tokens without an nbf claim are unaffected.
  • Upgrade guide (4.23) — note under camel-oauth. It also says that the servlet backend does not read the
    leeway from configuration (clock-skew-seconds feeds only the SPI), and shows how to raise it on the
    OAuth instance for identity providers whose clock runs ahead and which issue nbf == iat.

Tests

  • UserProfileTest — a token with a future nbf is rejected, a token whose nbf has passed is accepted,
    and the configured leeway is honored (accepted within it, rejected beyond it).
  • ServletOAuthTokenCredentialsTest (new) — the servlet bearer path, ServletOAuth.authenticate(TokenCredentials),
    rejects a token before its nbf and accepts it afterwards, without contacting an identity provider.
  • The new tests fail when the check is removed, and when the leeway is ignored.
  • mvn clean install in components/camel-oauth: 141 tests, 0 failures (the 7 skipped are the existing
    Keycloak-environment tests). Full reactor mvn clean install -DskipTests -DskipITs: green.

The backports to camel-4.22.x and camel-4.18.x will follow once this is merged, together with the matching
4.22 / 4.18 upgrade-guide notes on main.

JIRA: https://issues.apache.org/jira/browse/CAMEL-25022

Claude Code on behalf of oscerd

🤖 Generated with Claude Code

…g bearer tokens on the servlet backend

UserProfile.verifyToken() now rejects a token whose nbf (not before) claim is
later than the current time plus the JWTOptions leeway (default 0), as RFC 7519
section 4.1.5 requires. The servlet backend previously evaluated only exp; the
Vert.x backend and the OAuthTokenValidationFactory SPI already evaluate nbf.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solid fix. The nbf check is RFC 7519 §4.1.5 compliant, correctly applies the configured leeway, and is properly guarded against absent claims. The existing expired() / exp asymmetry (no leeway on staleness check) is pre-existing and out of scope. Tests cover rejection, acceptance, and leeway boundary — adequate. Upgrade guide is accurate.

Milestone should be set to 4.23.0.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-oauth
  • docs

🔬 Scalpel shadow comparison — Scalpel: 9 of 695 tested, 26 compile-only — current: 9 all tested

Maveniverse Scalpel detected 9 affected modules (current approach: 9).

Skip-tests mode would test 9 modules (2 direct + 8 downstream), skip tests for 26 (generated code, meta-modules)

Modules Scalpel would test (9)
  • camel-jbang-mcp ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-mcp ← downstream of org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-route-parser ← downstream of org.apache.camel:camel-route-parser
  • camel-jbang-plugin-tui ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-validate ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-launcher-container ← downstream of org.apache.camel:camel-launcher
  • camel-oauth ← components/camel-oauth/src/main/java/org/apache/camel/oauth/UserProfile.java, components/camel-oauth/src/test/java/org/apache/camel/oauth/UserProfileTest.java, components/camel-oauth/src/test/java/org/apache/camel/oauth/jakarta/ServletOAuthTokenCredentialsTest.java
  • camel-yaml-dsl-validator ← downstream of org.apache.camel:camel-catalog
  • camel-yaml-dsl-validator-maven-plugin ← downstream of org.apache.camel:camel-yaml-dsl-validator
Modules with tests skipped (26)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • dummy-component

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

All tested modules (36 modules, 5m 32s total)

Total reactor time: 5m 32s

Module Duration Status
Camel :: Launcher 51.5s SUCCESS
Camel :: JBang :: MCP 39.5s SUCCESS
Camel :: JBang :: Plugin :: TUI 31.4s SUCCESS
Camel :: OAuth 27.7s SUCCESS
Camel :: Catalog :: Camel Catalog 23.1s SUCCESS
Camel :: YAML DSL 18.3s SUCCESS
Camel :: Component DSL 18.0s SUCCESS
Camel :: Docs 15.0s SUCCESS
Camel :: JBang :: Plugin :: Kubernetes 14.7s SUCCESS
Camel :: YAML DSL :: Validator 9.8s SUCCESS
Camel :: Catalog :: Camel Report Maven Plugin 9.7s SUCCESS
Camel :: Kamelet Main 9.0s SUCCESS
Camel :: YAML DSL :: Deserializers 8.5s SUCCESS
Camel :: Catalog :: Camel Route Parser 8.2s SUCCESS
Camel :: JBang :: Plugin :: Testing 7.7s SUCCESS
Camel :: YAML DSL :: Validator Maven Plugin 6.9s SUCCESS
Camel :: All Components Sync point 5.4s SUCCESS
Camel :: JBang :: Plugin :: Validate 5.0s SUCCESS
Camel :: YAML DSL :: Maven Plugins 3.4s SUCCESS
Camel :: Catalog :: Maven 3.3s SUCCESS
Camel :: Catalog :: Suggest (deprecated) 2.6s SUCCESS
Camel :: Assembly 2.0s SUCCESS
Camel :: Catalog :: Dummy Component 1.7s SUCCESS
Camel :: JBang :: Plugin :: Edit 1.4s SUCCESS
Camel :: Coverage 1.4s SUCCESS
Camel :: JBang :: Main 1.4s SUCCESS
Camel :: JBang :: Integration tests 1.3s SUCCESS
Camel :: JBang :: Plugin :: Generate 1.0s SUCCESS
Camel :: Catalog :: Console 0.8s SUCCESS
Camel :: Endpoint DSL :: Support 0.7s SUCCESS
Camel :: Launcher :: Container 0.6s SUCCESS
Camel :: JBang :: Plugin :: MCP 0.6s SUCCESS
Camel :: JBang :: Plugin :: Route Parser 0.6s SUCCESS
Camel :: Endpoint DSL n/a
Camel :: Integration Tests n/a
Camel :: JBang :: Core n/a

Top 20 slowest modules:

  • Camel :: Launcher (51.5s)
  • Camel :: JBang :: MCP (39.5s)
  • Camel :: JBang :: Plugin :: TUI (31.4s)
  • Camel :: OAuth (27.7s)
  • Camel :: Catalog :: Camel Catalog (23.1s)
  • Camel :: YAML DSL (18.3s)
  • Camel :: Component DSL (18.0s)
  • Camel :: Docs (15.0s)
  • Camel :: JBang :: Plugin :: Kubernetes (14.7s)
  • Camel :: YAML DSL :: Validator (9.8s)
  • Camel :: Catalog :: Camel Report Maven Plugin (9.7s)
  • Camel :: Kamelet Main (9.0s)
  • Camel :: YAML DSL :: Deserializers (8.5s)
  • Camel :: Catalog :: Camel Route Parser (8.2s)
  • Camel :: JBang :: Plugin :: Testing (7.7s)
  • Camel :: YAML DSL :: Validator Maven Plugin (6.9s)
  • Camel :: All Components Sync point (5.4s)
  • Camel :: JBang :: Plugin :: Validate (5.0s)
  • Camel :: YAML DSL :: Maven Plugins (3.4s)
  • Camel :: Catalog :: Maven (3.3s)

⚙️ View full build and test results

@oscerd oscerd added this to the 4.23.0 milestone Sep 25, 2026

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @oscerd — a correct, well-tested fix that brings the servlet backend in line with Vert.x and the SPI validator.

A small doc point: the upgrade note refers to the leeway on JWTOptions, but on the servlet backend ServletOAuth builds the OAuthConfig from camel.oauth.* properties and nothing sets the leeway. It can only be changed from code (oauth.getOAuthConfig().getJWTOptions().setLeeway(n)), and clock-skew-seconds applies only to the SPI validator. Some identity providers issue nbf == iat, so a provider clock running slightly ahead would now reject fresh tokens with the default of 0. Could the note say how to set it (or should a follow-up expose a property)?

Nit: this adds a fourth === camel-oauth heading right after the existing one. Merging it into that section, or giving it a specific title, would read better.

This review was generated by an AI agent on behalf of davsclaus and may contain inaccuracies. Please verify all suggestions before applying.

Comment thread docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc Outdated
…e servlet backend

ServletOAuth.discoverOAuthConfig only sets the issuer on JWTOptions, so the
leeway stays at 0 and clock-skew-seconds does not reach it. Show how to set
it on the OAuth instance for identity providers whose clock runs ahead.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review after 8eade5a. @davsclaus asked how users can raise the nbf leeway on the servlet backend — addressed: the upgrade guide now explains that clock-skew-seconds does not feed UserProfile, and shows the getJWTOptions().setLeeway(n) call.

Minor: this adds a fourth === camel-oauth heading in the upgrade guide (line 1847) right after the existing one (line 1824). Merging into the existing section would read better, but it's cosmetic and doesn't block.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@oscerd
oscerd requested a review from davsclaus September 28, 2026 16:41
@davsclaus davsclaus added the bug Something isn't working label Sep 28, 2026
@davsclaus
davsclaus merged commit 4121a74 into apache:main Sep 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working components docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants