Skip to content

thomas-hochbichler/ropc-alternative-flows-poc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ROPC Alternative Flows PoC

Companion repository for ROPC Is Dead: How to Get User Tokens Without It.

RFC 9700 (January 2025) prohibits OAuth2 Resource Owner Password Credentials (grant_type=password) — the strongest "MUST NOT" in IETF vocabulary. OAuth 2.1 removes it entirely. This PoC demonstrates the two industry-standard replacements that CLIs like Azure CLI and AWS CLI already use:

  • Authorization Code + PKCE (default) — opens a browser, catches the callback on localhost
  • Device Authorization Grant (--use-device-code) — displays a URL and code for headless environments

Architecture

flowchart LR
    CLI["CLI Client\n(Spring Boot CLI)"]
    KC["Keycloak 26\n(Auth Server)\nPort 8180"]
    Browser["Browser\n(User)"]
    RS["Resource Server\nPort 8080"]

    CLI -- "OAuth2 flow" --> KC
    Browser -- "Login / Approve" --> KC
    CLI -- "Bearer token" --> RS
Loading
Component Description
cli-client Spring Boot CLI app with two OAuth2 flows. No web server — uses java.net.http.HttpClient for all HTTP calls.
resource-server Spring Boot OAuth2 Resource Server. Validates JWTs against Keycloak and exposes GET /api/userinfo.
Keycloak 26 Authorization server with pre-configured realm (ropc-demo), public client (cli-client), and test user. ROPC is explicitly disabled.

Prerequisites

  • JDK 17+
  • Maven 3.8+
  • Docker & Docker Compose

Quick Start

1. Start Keycloak

docker compose up -d

Wait ~30 seconds for the realm import to complete. Keycloak runs on http://localhost:8180 (admin/admin).

2. Start the Resource Server

cd resource-server
mvn spring-boot:run

The resource server starts on port 8080 and validates JWTs issued by Keycloak.

3a. Auth Code + PKCE (default)

cd cli-client
mvn spring-boot:run

What happens:

  1. The CLI generates a PKCE code verifier and challenge
  2. A temporary HTTP server starts on localhost (port 6363, fallback 6364/6365)
  3. Your browser opens the Keycloak login page
  4. You log in as testuser / testpassword
  5. Keycloak redirects back to localhost with an authorization code
  6. The CLI exchanges the code + PKCE verifier for an access token
  7. The CLI calls the protected /api/userinfo endpoint and prints the result

3b. Device Authorization Grant

cd cli-client
mvn spring-boot:run -Dspring-boot.run.arguments="--use-device-code"

What happens:

  1. The CLI requests a device code from Keycloak
  2. The CLI displays a verification URL and user code
  3. You open the URL in any browser (even on a different device)
  4. You enter the code and log in as testuser / testpassword
  5. The CLI polls until authorization completes
  6. The CLI calls the protected /api/userinfo endpoint and prints the result

Expected Output

{"sub":"...","preferred_username":"testuser","email":"testuser@example.com","scope":"openid profile","issued_at":"...","expires_at":"..."}

Keycloak Configuration

The realm is auto-imported from keycloak/realm-export.json:

Setting Value
Realm ropc-demo
Client cli-client (public)
Auth Code flow Enabled
Device flow Enabled
ROPC (Direct Access Grants) Disabled
Redirect URIs http://localhost:6363/*, http://localhost:6364/*, http://localhost:6365/*
Test user testuser / testpassword

Why These Flows?

ROPC was one POST request — simple but dangerous. The client saw the user's password, MFA couldn't work, and the authorization server lost control of the login experience.

Auth Code + PKCE keeps the same convenience (browser opens automatically) while ensuring the CLI never sees the password. The PKCE extension prevents authorization code interception.

Device Authorization Grant solves the headless case — SSH sessions, containers, CI runners — where no browser is available on the same machine. The user authenticates on any device with a browser.

This dual-mode pattern (PKCE by default, device code as fallback) is what Azure CLI, AWS CLI, and GitHub CLI converged on. See the companion article for the full decision tree, HTTP-level examples, and migration checklist.

License

MIT

About

PoC: Auth Code + PKCE and Device Code flows replacing ROPC (companion to blog post)

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors

Languages