Cloudflare Workers OAuth Provider: Review of an AI-Assisted OAuth Library
In March, Cloudflare released a new library: the Workers OAuth Provider. This library implements the provider side of the OAuth 2.1 protocol with PKCE support, specifically designed for Cloudflare Workers. What makes this release particularly interesting is that it was largely written with the assistance of Claude, Anthropic's AI model.
Critical Security Vulnerability
Before diving into the implementation details, it's important to note a critical security vulnerability that was recently discovered and fixed in the library. The implementation failed to properly validate the redirect_uri
parameter against the allowed list of redirect URIs for the given client registration during the authorization flow.
This vulnerability could allow an attacker to:
- Target victims who had previously authorized with a server built on workers-oauth-provider
- Trick the victim into visiting a malicious website
- Potentially steal the victim's credentials
- Impersonate the victim on the OAuth server
The vulnerability was particularly dangerous because:
- It only implemented the redirect URI validation during token exchange, not during the initial authorization flow
- Many applications built on top of the library implement automatic re-authorization logic
- The validation during the authorization flow is the more critical check
The author of the library has acknowledged this oversight, noting that while they were aware of this basic OAuth requirement and had thought about it during design, they "somehow forgot to actually make sure the check was in the code." This vulnerability has been fixed in PR #26.
The AI-Assisted Development Process
The development of this library represents a fascinating case study in AI-assisted software development. According to Kenton Varda, a Cloudflare engineer who led the project:
"I started this project on a lark, fully expecting the AI to produce terrible code for me to laugh at. And then, uh... the code actually looked pretty good. Not perfect, but I just told the AI to fix things, and it did. I was shocked."
The development process followed a rigorous approach:
- Initial code generation by Claude
- Thorough review by Cloudflare engineers
- Cross-referencing with relevant RFCs
- Iterative improvements through additional AI prompting
- Final security review by experts
Technical Implementation Review
Code Structure and Organization
The library's code is contained in a single file, which is typical for LLM-generated code. However, it maintains a reasonable structure with proper class organization and minimal unnecessary comments. The initial implementation shows promise, but there are several areas of concern that warrant attention.
Security Concerns
CORS Implementation
One of the first red flags is the CORS implementation that effectively disables the same-origin policy for all origins:
private addCorsHeaders(response: Response, request: Request): Response {
const origin = request.headers.get('Origin');
if (!origin) return response;
const newResponse = new Response(response.body, response);
newResponse.headers.set('Access-Control-Allow-Origin', origin);
newResponse.headers.set('Access-Control-Allow-Methods', '*');
newResponse.headers.set('Access-Control-Allow-Headers', 'Authorization, *');
newResponse.headers.set('Access-Control-Max-Age', '86400');
return newResponse;
}
While this implementation might be acceptable in specific contexts, it's generally considered a security risk. The commit history reveals this was a human decision rather than an LLM suggestion.
Missing Security Headers
The implementation lacks several standard security headers that are crucial for API security:
- No
X-Content-Type-Options: nosniff
header - Missing HTTP Strict Transport Security (HSTS) headers
- These omissions could potentially lead to security vulnerabilities, particularly in how browsers interpret responses
OAuth Implementation Issues
Implicit Grant Support
The library implements the deprecated "implicit" grant type (removed in OAuth 2.1) to support public clients. This is unnecessary, especially since the code already implements PKCE and has relaxed CORS settings. The commit history suggests this was an LLM-suggested solution that wasn't properly vetted against OAuth 2.1 specifications.
Basic Auth Implementation
The Basic auth implementation contains classic OAuth bugs:
- Incorrect handling of URL encoding (a common mistake in OAuth implementations)
- Potential issues with client secrets containing colons
- While these might not be exploitable in this specific implementation (due to controlled client ID/secret generation), they indicate a lack of deep OAuth expertise
Encryption Implementation
The encryption implementation for the token store provides an interesting case study in AI-human collaboration. The process of implementing secure encryption for the props
stored in Grant
and Token
records went through several iterations, documented in the commit history:
Initial Prompt: "I would like to encrypt the
props
stored inGrant
andToken
records. It should be encrypted such that you need a valid token to decrypt. This is a bit tricky since there are multiple valid tokens over time: there's the authorization code, the refresh tokens (which rotate), and individual access tokens. We don't want to repeatedly re-encryptprops
. Instead, we should encrypt in once, with a symmetric key, and then we should store that key "wrapped" for each token, while the token is valid. Please use WebCrypto to implement all cryptography."
During implementation, the engineer realized an important design consideration:
Design Realization: "One thing I forgot to note: The
listUserGrants()
helper function will no longer be able to return theprops
, since it doesn't have any token with which to decript it. That's OK:props
need only be delivered to the app upon an authorized API request. We should actually changelistUserGrants()
to make it return a narrower representation of a grant. Right now it returns the entire grant record from storage, but we really only need it to returnid
,clientId
,userId
,scope
,metadata
, andcreatedAt
. We don't need to return any of the token IDs or code challenge information."
Claude's implementation revealed a critical security flaw:
Security Flaw Discovery: "There's a security flaw in the way you wrap keys for tokens: You used a SHA-256 hash of the token as the key material for the wrapping. However, SHA-256 is also how we compute "token IDs". With this construction, someone would be able to unwrap the keys using only the token ID, which is stored alongside the wrapped keys, hence all keys can be trivially unwrapped. To fix this, we need to compute the hash differently when computing the key material for wrapping, in such a way that it's not possible to derive the key material from the token ID."
The solution went through several iterations:
First Attempt: Claude initially tried to solve this by switching to using PBKDF2 with 100,000 iterations to derive the key material.
Performance Consideration: "PDKDF2 with 100000 iterations would be very expensive. This would be important if the input were a low-entropy password, but is not necessary for high-entropy input. Instead of PBKDF2, let's use a SHA-256 HMAC, with a static HMAC key (which essentially acts as the "salt")."
Final Optimization: "This looks pretty good, but for performance, let's define WRAPPING_KEY_HMAC_KEY as a 32-byte array, so that it doesn't have to be encoded or hashed down to the right size (as HMAC would do for larger keys). Here are 32 bytes of hex which I have chosen randomly, to use as the HMAC key: 22 7e 26 86 8d f1 e1 6d 80 70 ea 17 97 5b 47 a6 82 18 fa 87 28 ae de 85 b5 1d 4a d9 96 ca ca 43"
Another revealing commit shows the importance of expert review in security-critical code:
Backup Key Issue: "I noticed you are storing a "backup" of the encryption key as
encryptionKeyJwk
. Doesn't this backup defeat the end-to-end encryption, because the key is available in the grant record without needing any token to unwrap it?"
This is a particularly insightful catch that demonstrates why expert review is crucial. A non-expert reviewer might not even understand what this means, let alone spot the security implications. The backup key would have completely defeated the purpose of the end-to-end encryption by making the key available without requiring a valid token.
This process demonstrates how AI can be a valuable collaborator in implementing complex security features, but also highlights the importance of human expertise in:
- Identifying security flaws
- Making performance trade-offs
- Understanding cryptographic primitives
- Making architectural decisions
- Catching subtle security issues that might not be obvious to non-experts
The final implementation shows a good balance between security and performance, using a static HMAC key for key wrapping while maintaining the security properties needed for the token store.
Testing and Quality Assurance
The library's test coverage is inadequate for a security-critical authentication service:
- Missing tests for OAuth specification MUST/MUST NOT requirements
- Insufficient coverage of abuse cases
- Basic functionality tests only
- Parameter validation appears to be incomplete
AI Limitations in Practice
The commit history reveals an interesting case where the AI's limitations became particularly apparent:
Manual Bug Fix: "Fix Claude's bug manually. Claude had a bug in the previous commit. I prompted it multiple times to fix the bug but it kept doing the wrong thing. So this change is manually written by a human." (commit 60197d5)
This is a telling example of how even with multiple attempts and clear instructions, the AI sometimes fails to understand and fix certain issues. The engineer had to step in and implement the fix manually, demonstrating that AI assistance has its limits, especially in complex security implementations. This case also highlights the importance of having human experts who can:
- Recognize when the AI is not understanding the problem correctly
- Know when to take over and implement fixes manually
- Understand the underlying issues well enough to implement correct solutions
- Document the limitations of AI assistance for future reference
Lessons Learned
-
LLM Limitations: The project demonstrates that LLMs can produce decent code but require expert oversight, especially for security-critical systems.
-
Human Expertise Required: The commit history shows that human engineers needed to correct several security-critical issues that the LLM introduced. The redirect URI validation vulnerability demonstrates that even experienced developers can miss critical security checks.
-
Testing Importance: The lack of comprehensive testing highlights the need for thorough security testing in authentication systems, particularly for well-known OAuth vulnerabilities.
-
Specification Knowledge: The implementation shows that deep knowledge of OAuth specifications is crucial for building secure authentication systems.
Conclusion
While the Cloudflare Workers OAuth Provider represents an interesting experiment in AI-assisted development, it's not yet ready for production use. Building a secure OAuth provider requires extensive testing, threat modeling, and security review - aspects that are currently lacking in this implementation.
The project demonstrates that while LLMs can be valuable coding assistants, they should not be trusted to implement security-critical systems without extensive human oversight and expertise.