OpenID Connect authentication for CLI applications
TL;DR
- repository with examples (api gateway, cli app, web app / frontend, docker-compose) is here: https://github.com/kharkevich/web-cli-oidc-sso/
- sequence diagram is down below
Auth process overview
The sequence diagram outlines the authentication process. Here’s a step-by-step breakdown:
- User Initiates Authentication. The user runs cli-app auth in their terminal. The “auth” argument is needed to trigger the authentication process explicitly.
- Exchange Code Generation. The CLI app communicates with the API Gateway to generate a unique exchange code. This code is essential for securely linking the CLI application, the user’s browser session and the OIDC auth flow.
- User Action in Browser. The CLI app presents the exchange code along with a URL, instructing the user to open a browser and navigate to the provided link. This URL directs the user to the API Gateway.
- OIDC Provider Interaction. Upon visiting the link, the user is redirected to the OIDC provider’s authentication page. The user completes the login process, which includes providing credentials and verifying their identity (by second factor for example).
- Authentication Flow Completion. After successful authentication, the OIDC provider redirects the user back to the API Gateway, appending it with an authorization code that will be used for token exchange.
- JWT Exchange. The API Gateway uses the provided authorization code to request a JWT (JSON Web Token). This JWT is then made accessible to the CLI app.
- Secure Session Establishment. The CLI app retrieves the JWT and then uses it for signing each request to establish a secure session for subsequent interactions with private APIs.
Advantages of the Flow
Security: The exchange code ensures that the CLI app cannot directly obtain a JWT without user involvement, preventing unauthorized access.
User-Friendly: By leveraging the browser for authentication, the flow ensures familiarity and reduces friction for the user.
Standardized: OIDC’s standardized approach guarantees compatibility with a wide range of identity providers.
Under the hood
API Gateway represents a Python application based on top of FastAPI and Authlib.
API protection is implemented by simple middleware injected into the protected router and mounted to the main application
1 | app = FastAPI() |
In this custom middleware, I do several validations:
- JWT validation
- Check for presenting some required claims, group membership in my example
1 | class AccessValidatorMiddleware(BaseHTTPMiddleware): |
This is add low overhead, but provide simple and reliable way to expose private API.
Side effects
JWT protection works perfectly not only for CLI applications, you can use it for protection web applications (for BFF for example) or for micro-services communications.
To expand this example you can run React front-end application and ensure that you unable to interact with protected API until you authorized, and implementation authorization is simple and straightforward.
Outcome
OIDC offers a streamlined and secure way to handle CLI authentication. By decoupling user credentials from the CLI app and leveraging JWTs, this flow ensures robust security while maintaining user convenience. For more details, check out the GitHub repository and the sequence diagram.
OIDC CLI SSO Demo
First run of cli-app
cli-app calls gateway, open browser automatically, receive JWT after successfully authorization and call to private API hello
cli-app screen cast
api gateway logs
Call to prohibited resources
cli-app with valid JWT token calls to private API hello, but JWT failed with required claims in token, and denied in access to API
cli-app screen cast
api gateway logs
Expired, broken or invalid JWT
call to private api with expired, broken or invalid JWT with subsequent automatic re-authentication