How a Jwt Is Securely Delivered to a Client Using the Pkce Flow
To understand how a jwt is securely delivered to a client using the pkce flow, pair a secret verifier with a hashed challenge. The server checks both values before it sends the signed token back. Engineering teams often set up this flow for mobile and web apps. Still, teams still grant broad roles to the final token itself. Broad token permissions let a logged-in user run risky commands against production systems. How a jwt is securely delivered to a client using the pkce flow Public clients
End-to-End Encryption + Data Flow Diagrams (Security): the complete guide
Architecture patterns, implementation strategies, and security best practices. Delivered to your inbox.
To understand how a jwt is securely delivered to a client using the pkce flow, pair a secret verifier with a hashed challenge. The server checks both values before it sends the signed token back. Engineering teams often set up this flow for mobile and web apps. Still, teams still grant broad roles to the final token itself. Broad token permissions let a logged-in user run risky commands against production systems.
How a jwt is securely delivered to a client using the pkce flow
Public clients like browser apps or CLI tools cannot store static secrets safely. Anyone can inspect the app package and steal a hardcoded key. Proof Key for Code Exchange solves this problem by creating a fresh secret for each login.
First, the client app creates a random string called the code verifier. The app keeps this verifier in memory and never sends it in the first step. Next, the app hashes the verifier to build a code challenge. The app sends the user to the login server along with this challenge and the hash method.
The user logs in and approves the request on the identity server. The server stores the code challenge and sends a temporary code back to the client. An attacker on the device might intercept this temporary code during the redirect. Still, the code alone cannot buy a JSON Web Token.
To finish the exchange, the client sends the temporary code and the plain verifier to the token endpoint. The server hashes the plain verifier using the chosen hash method. It compares the result to the challenge from the first step. If both hashes match, the server sends the signed JWT over an encrypted channel.
Why always use S256 for the code challenge
The spec supports two challenge methods: plain and SHA-256. In the plain method, the challenge is identical to the verifier. If an attacker reads the initial request on the network, they see the secret right away.
Teams should always enforce the S256 method on the identity server. With S256, the app sends a one-way cryptographic hash in the first request. Even if an attacker sees the challenge in transit, they cannot reverse the hash to find the verifier.
End-to-End Encryption + Data Flow Diagrams (Security): architecture patterns and best practices
Continue reading? Get the full guide.
Free. No spam. Unsubscribe anytime.
Once the client receives the JWT, it must store the token safely in memory. Storing tokens in browser local storage exposes them to harmful scripts on the page. Keeping tokens in memory limits the theft risk after delivery.
What the PKCE flow solves and where gaps remain
This dynamic exchange proves that the app asking for the token started the login. It blocks attackers who intercept redirect codes on phones, laptops, or shared networks. It also removes the need to ship static client secrets inside public apps.
Still, PKCE only secures the initial login and token delivery step. Once the client holds the JWT, the flow steps out of the way. The token often carries static scopes or broad role claims for its entire lifetime. PKCE decides who logs in, not what individual queries or commands do in flight.
If an engineer uses a CLI tool to get a token, that token grants full role permissions. The login server cannot see which database rows the user reads next. It cannot block a destructive command or rewrite sensitive fields like emails, phone numbers, card numbers, or national IDs.
Govern statements and responses across databases and APIs
Good config and scoped roles are needed setup. They do not check single queries in flight or mask sensitive fields in returned rows. Across Postgres, MySQL, SQL Server, MongoDB, ClickHouse, Kubernetes APIs, SSH, and internal HTTP endpoints, hoop.dev runs beside each supported service as an open-source proxy, a sidecar for your database or API.
First, hoop.dev guardrails block banned queries before they run. Then hoop.dev data masking rewrites matched sensitive values in responses in memory. The audit trail records every statement and verdict per resource. Furthermore, hoop.dev holds SOC 2 Type II and is open source on GitHub.
Frequently asked questions
Why do public clients need PKCE instead of a client secret?
Users can inspect the source files of browser, mobile, and CLI apps. Attackers can extract any static secret baked into the app build. PKCE generates a one-time secret in memory for every single login attempt.
Can an attacker steal the JWT if they intercept the authorization code?
No, the authorization code is useless without the matching code verifier. The client holds the verifier in memory and sends it directly to the token endpoint. Because the attacker never sees the verifier, the server rejects their token request.
Does PKCE replace the need to validate JWT signatures on the backend?
No, PKCE only protects the delivery of the token to the right client. Backend services must still check the token signature, expiration time, and issuer claim on every request. Signature checks prove that the identity server issued the token and nobody altered it.
Related guides
In this post