Skip to content

Feature/oauth pkce backend#158

Open
ronibhakta1 wants to merge 17 commits intoArchiveLabs:mainfrom
ronibhakta1:feature/oauth-pkce-backend
Open

Feature/oauth pkce backend#158
ronibhakta1 wants to merge 17 commits intoArchiveLabs:mainfrom
ronibhakta1:feature/oauth-pkce-backend

Conversation

@ronibhakta1
Copy link
Copy Markdown
Collaborator

@ronibhakta1 ronibhakta1 commented Feb 16, 2026

closes #159
This pull request introduces significant improvements to the OAuth PKCE authentication flow in Lenny, adds a client registration utility, and enhances environment configuration and rate limiting. The main changes enable easier OAuth client registration, improve security and token management, and update documentation and proxying for OAuth endpoints.

OAuth PKCE Flow Enhancements:

  • Added a new oauth-register Makefile target and docker/utils/register_client.sh script for interactive OAuth client registration, allowing users to easily register clients and specify redirect URIs. [1] [2]
  • Introduced a background task in lenny/app.py to periodically clean up expired auth codes and refresh tokens, improving token lifecycle management.
  • Updated authentication logic to support JWT access tokens from PKCE flow, including fallback decoding and email extraction.

Documentation Improvements:

  • Expanded README.md with a new section on OAuth client registration, including interactive and non-interactive instructions and PKCE flow testing steps. [1] [2]

Environment and Configuration Updates:

  • Added LENNY_EMAIL_ENCRYPTION_SALT to environment configuration and propagated it through docker/configure.sh and lenny/configs/__init__.py. [1] [2] [3] [4]

Rate Limiting Integration:

  • Integrated slowapi rate limiter in lenny/app.py and added a dedicated module for rate limiting. [1] [2]

Proxy and Routing Adjustments:

  • Updated docker/nginx/conf.d/lenny.conf to proxy /v1/oauth requests to the API, ensuring proper routing for OAuth endpoints.
  • Registered the new OAuth router in lenny/app.py and updated LennyDataProvider to include the OAuth URL. [1] [2]

These changes collectively make OAuth client registration and PKCE authentication easier, improve security and maintainability, and enhance documentation for developers.

@ronibhakta1 ronibhakta1 self-assigned this Feb 16, 2026
ronibhakta1 and others added 15 commits February 27, 2026 14:55
Added section for syncing Lenny OPDS feed with Internet Archive's Bookserver app.
…rchiveLabs#154)

* refactor: Delegate catalog, publication, and empty feed generation to `LennyDataProvider` methods, removing local helper functions `_navigation` and `_build_empty_feed`.

* feat: Skip several dynamic authentication tests due to missing methods in `pyopds2_lenny`.

* fix: Update OAuth redirect URLs to use query parameters instead of fragments
… a `testing_access_key` to OTP issue and redeem requests.
…rvices, and API routes, alongside database configuration and timezone adjustments.
…with Lenny-specific acquisition links, including PKCE and direct authentication for borrowing.
…2 acquisition and post-borrow links with OAuth PKCE authentication.
else:
# Old format, just email (no IP verification possible)
return data
except BadSignature:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious what is happening here. Shouldn't we error out on bad signatures?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two things are happning here

  1. Old version of verifying the cookie's if there is a Ip address which was optional to do the check's (for backward compablity)
  2. Now if there are not such things we can move to the JWT to fech the session and extract required thing's

return AES.new(key, AES.MODE_GCM, nonce=nonce)
return AES.new(key, AES.MODE_GCM)

def encrypt_email(email: str) -> str:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the encrypt/decrypt email for?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The encrypt/decrypt functions are used to protect user email addresses at rest in the database. Emails are encrypted using AES-GCM before being stored, so that the raw email address is not stored in plaintext. This helps reduce exposure of sensitive user data in case of a database leak. When the application needs to use the email (for example token refresh or registration), it is decrypted using the same derived key. The hash_email function is separate and is used for deterministic lookups/indexing where we don’t need to recover the original email.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, and the key lives in memory during the lifetime of the server process? So if it restarts, the key becomes invalid?

That seems ok.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right. But we still make sure the stored data has a prefix to keep the backword's compablity



@router.post("/token")
@limiter.limit("5/minute")
Copy link
Copy Markdown

@MarcCoquand MarcCoquand Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested manually that the rate limiter works?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth 2.0 Implicit --> OAuth 2.0 PKCE

2 participants