惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Know Your Adversary
Know Your Adversary
博客园 - 叶小钗
量子位
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园 - 【当耐特】
博客园 - Franky
有赞技术团队
有赞技术团队
博客园 - 聂微东
腾讯CDC
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Jina AI
Jina AI
Last Week in AI
Last Week in AI
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Cloudbric
Cloudbric
WordPress大学
WordPress大学
W
WeLiveSecurity
V2EX - 技术
V2EX - 技术
博客园_首页
S
Security @ Cisco Blogs
The Last Watchdog
The Last Watchdog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Security Latest
Security Latest
L
Lohrmann on Cybersecurity
T
Threat Research - Cisco Blogs
Forbes - Security
Forbes - Security
宝玉的分享
宝玉的分享
The Register - Security
The Register - Security
The Hacker News
The Hacker News
B
Blog RSS Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
Schneier on Security
Schneier on Security
T
Troy Hunt's Blog
The GitHub Blog
The GitHub Blog
Hacker News: Ask HN
Hacker News: Ask HN
Spread Privacy
Spread Privacy
Hugging Face - Blog
Hugging Face - Blog
博客园 - 三生石上(FineUI控件)
GbyAI
GbyAI
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
罗磊的独立博客
Blog — PlanetScale
Blog — PlanetScale
M
MIT News - Artificial intelligence
T
Tor Project blog
S
Security Affairs
Security Archives - TechRepublic
Security Archives - TechRepublic
NISL@THU
NISL@THU
P
Proofpoint News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
What Is PKCE, How It Works & Flow Examples
Mrunank Pawa · 2026-05-22 · via DEV Community

This blog was originally published on Descope.

You'd think the most secure OAuth flow wouldn't need a patch, but the standard Authorization Code flow has a blind spot. It can't guarantee that the app redeeming an authorization code is the same one that requested it. That gap opens the door to interception and Cross-Site Request Forgery (CSRF) attacks. Proof Key for Code Exchange (PKCE) closes it.

In this guide, we'll explore what PKCE is and how it stops these attacks. We'll break down the standard Authorization Code flow, pinpoint where PKCE adds value, and examine why organizations are embracing it, even before it's officially mandatory in the latest OAuth standard.

Main points

  • Authorization Code flow has a verification gap. It can't confirm the app exchanging the code is the one that requested it.
  • PKCE binds request and token exchange. A dynamic code challenge verifies the legitimacy of the client.
  • Public clients need it, all clients benefit. PKCE protects apps with or without client secrets.
  • PKCE is mandatory in OAuth 2.1. It's no longer optional—it's the new standard.

What is PKCE?

PKCE, pronounced "pixie," is a security extension for OAuth 2.0's Authorization Code flow. While it's designed for scenarios where the client secret cannot be securely stored, all applications can benefit from PKCE. In fact, while it's already recommended in the best practices for OAuth, PKCE is a requirement for all clients using the in-development OAuth 2.1 specification.

As an enhancement for standard OAuth, PKCE can benefit all types of applications for two big reasons:

  • CSRF attacks: When a malicious site or app initiates an authorization request without the user's knowledge.
  • Authorization code interception/injection: When an attacker intercepts an authorization code and exchanges it for access tokens before the legitimate application does.

The standard Authorization Code flow and where PKCE steps in

OAuth provides several different "grant types"—standardized methods for obtaining access tokens. Grant types are associated with different scenarios, with each one offering a different balance of security and convenience. One of these is the Authorization Code grant type, widely considered to be the most versatile and secure of the bunch.

Authorization Code flow

The "vanilla" Authorization Code flow is meant for applications that can maintain a server-side component to securely store credentials. Here's how it works:

Fig: Authorization Code Flow

  1. User initiates login: The user chooses to grant your application permissions via OAuth, such as by choosing "Log in with Service (e.g., Google)" in your app.
  2. Authorization Code request: The client requests an Authorization Code from the authorization server, including information about what the app is and what permissions it's requesting.
  3. Prompt for consent: The authorization server asks the user to authenticate and provide consent for the app to access their resources.
  4. User authentication: The user logs in to the authorization server and approves the requested permissions.
  5. Authorization code return: The authorization server redirects the user back to your application with a temporary Authorization Code
  6. Token exchange: Your application sends this code to the authorization server along with your app credentials.
  7. Access token issued: The authorization server validates everything and returns ID and access tokens
  8. Resource access: Your application uses the access token to request protected resources

In this flow, the application never sees the user's credentials. Instead, the user authenticates directly with the authorization server, which then provides the app with a temporary authorization code.

The security gap

The standard Authorization Code flow has a fundamental flaw: there's no way to verify that the client exchanging an authorization code for tokens is the same client that initiated the request. This raises several concerns:

  • An attacker who intercepts the authorization code can use it to obtain access tokens because there's no verification that ties the code to the original requesting application.
  • Even if the application uses a client secret (essentially a password shared between the app and authorization server), this only proves the client's identity, not that this specific client originally requested this specific authorization code.
  • Since there's nothing binding the initial request to the token exchange, the flow is also vulnerable to CSRF attacks, in which a user could be tricked into initiating an unintended authorization flow.

This security gap affects all types of applications, though it's especially problematic for clients that can't securely store client secrets. This is where PKCE comes in, binding the initial authorization request and the token exchange.

PKCE flow

Without PKCE, OAuth authorization code flows don't have a way to verify which specific client sent this specific request. To understand how PKCE eliminates this vulnerability, we merely need to look at its name: Proof Key for Code Exchange, meaning you need proof you originated the authorization request to exchange the code for tokens.

To achieve this, PKCE has the requesting application create a new type of secret, a "code verifier." This is used to create a "code challenge," which the authorization server uses to confirm which app sent the request. Here's how it works:

Fig: Authorization Code Flow With PKCE

  1. User initiates login: Just like in a standard Authorization Code flow, the user initiates the process by selecting the prompt associated with granting your application permissions via OAuth, like "Log in with Service (e.g., Google)."
  2. Code verifier creation: Before starting the flow, your application generates a random secret. This is not the same as a client secret—it's a special component called a "code verifier." Client secrets can still be used alongside it. Your application also creates a "code challenge" by transforming the verifier, usually by hashing it (a one-way process that can't be reversed or decoded).
  3. Authorization code request: The application requests an authorization code from the server and includes the code challenge (along with the hashing method, like SHA-256).
  4. Prompt for user consent: The authorization server prompts the user to authenticate and provide consent for the requested permissions (same as standard flow).
  5. User authentication: The user logs in and approves the permissions (same as standard flow).
  6. Authorization code return: The authorization server redirects back to your application with the code.
  7. Token exchange (with verification): Your application sends the code to the authorization server along with the original code verifier.
  8. Server verification: The authorization server compares the previously shared code challenge to the recently shared original code verifier before issuing any tokens. For example, if the method used was hashing with SHA-256, the server will also hash the code verifier and ensure it matches the code challenge; the two strings should be the same.
  9. Access token issued: If the code verifier matches up with the code challenge, the authorization server returns ID and access tokens.
  10. Resource access: Your application can now use these tokens to request the necessary resources (as in the standard flow).

Using PKCE in your endpoints enables the authorization server to verify that the client requesting tokens is the same one that made the request. Even if an attacker intercepts the authorization code, they can't exchange it for tokens without the original code verifier. Only the legitimate application has this in its untransformed (e.g., unhashed) state.

PKCE in public vs. confidential clients

In OAuth terminology, clients are either "public" or "confidential" based on their ability to securely store credentials. Public clients are apps that cannot safely store a client secret because their code is fully exposed to the user or can be extracted easily. Public apps include:

  • Single-page apps (SPAs) running entirely in the browser
  • Native mobile apps
  • Certain types of desktop apps, like those that don't use TPMs (Trusted Platform Modules) to securely store credentials

Public clients need PKCE because they can't rely on client secrets for security. Confidential clients, on the other hand, can securely store credentials because they either run in controlled server environments or the code and secrets are otherwise inaccessible to end users. So, why would you want to use PKCE for a confidential client?

  • Protection against authorization code injection attacks and CSRF: As previously mentioned, CSRF and authorization code injection attacks are potential threats to all types of applications. OAuth 2.0 Best Practices recommend PKCE for confidential clients because it "provides strong protection against misuse and injection of authorization codes" and "prevents CSRF even in the presence of strong attackers."
  • Adjunctive security that complements (not replaces) client secrets: The OAuth PKCE spec makes no bones about it—PKCE is not a replacement for client secrets or authentication. While it was originally designed to protect public clients, PKCE proved useful as an add-on to existing mechanisms by preventing CSRF attacks, prompting the question: "Why not add PKCE if you can?"
  • Protection against implementation vulnerabilities: In the absence of PKCE, it's possible for a client implementation to fail at properly verifying state parameters (an OAuth mechanism used to deter CSRF attacks). Because PKCE is verified by the authorization server, it provides protection even when client-side verification is flawed or incomplete.

PKCE benefits

PKCE Benefit Public Clients Confidential Clients
Eliminates need for client secret ✅ Required — can't store secrets securely ❌ Still uses client secret
Prevents authorization code interception ✅ Essential to prevent token theft ✅ Adds an extra layer of protection
Mitigates CSRF attacks ✅ Protects flows in exposed environments ✅ Strengthens existing CSRF defenses
Recommended in OAuth 2.0 best practices ✅ Strongly recommended ✅ Strongly recommended
Required in OAuth 2.1 ✅ Mandatory ✅ Mandatory
Protects against poor client implementations ✅ Helps when state checks are missing or weak ✅ Useful fallback in misconfigured setups

PKCE use cases and examples

Although PKCE was originally developed to secure authorization code flows on public clients, the reasons for adoption can vary across use cases and application types. Even so, there are virtually no scenarios in which an additional layer of seamless security is unwelcome.

Ideal PKCE use cases include:

  • Native mobile applications: In the original PKCE scenario, native mobile apps are public clients that can't securely store secrets. Without PKCE, these applications couldn't use the authorization code flow without exposing credentials to anyone with the knowledge and tools to find them.
  • Single-page applications (SPAs): SPAs benefit from PKCE in the same way native mobile apps do: all their code runs in the browser, meaning there's no server-side storage for client secrets. SPAs rely on PKCE to use the authorization code flow safely.
  • Desktop applications: Some desktop applications can leverage TPMs and other mechanisms to secure client secrets even if the application runs entirely on a user device, but many don't have this design. Like other public apps, these desktop clients need PKCE to use the authorization code flow securely.
  • OAuth 2.0 best practices and 2.1 compliance: OAuth 2.0 best practices recommend PKCE be used for every client, not just public ones. OAuth 2.1, despite being in its draft stage, has already been adopted by many organizations. It makes PKCE mandatory.

PKCE and MCP adoption

The Model Context Protocol (MCP) is a standardized way for Large Language Models (LLMs) and AI agents to connect with external tools, APIs, and data sources. The authorization specification for MCP formally adopted OAuth 2.1, requiring developers leveraging the protocol to "implement OAuth 2.1 with appropriate security measures for both confidential and public clients." That means using PKCE.

Because MCP serves as the "universal remote" that serves up AI agents to connect with external tools, OAuth was the logical choice for authorization. OAuth already has a strong, proven foundation spanning over a decade, making developing a new standard just for AI use cases a moot point. OAuth 2.1 provides the latest and most secure set of requirements, and PKCE adds a crucial layer of protection to a budding ecosystem still finding its footing.

MCP's embrace of OAuth 2.1 (and thus PKCE) is particularly significant because of the AI protocol's widespread acceptance and sudden rise to prominence. It's already seen adoption by OpenAI's Agents SDK and industry leaders like Google, with the tech giant releasing their own "complementary" Agent2Agent protocol that can work hand-in-hand with MCP. Looking to the future, as MCP becomes more prevalent, so does PKCE.

No-hassle OAuth Authorization Code flows with PKCE

PKCE may sound like a complicated identity concept at first glance, but it's easily integrated with the right tools. Descope is a comprehensive external identity and access management solution that makes complex auth challenges drag & drop simple.

Descope can be configured as an OIDC Provider to easily add PKCE-based flows to your app. Our MCP Auth SDKs help make remote MCP servers OAuth-compliant by implementing OAuth, PKCE, dynamic client registration and more in just three lines of code.

Sign up for a Free Forever account with Descope to see how PKCE-enhanced OAuth flows can enhance your users' auth journey. Got questions about Descope? Book time with our auth experts.

Fig: Descope MCP Auth SDKs and APIs