-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add RFC for Bluesky (ATProto) OAuth #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
travis
wants to merge
4
commits into
main
Choose a base branch
from
feat/bluesky-oauth
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| # RFC: Bluesky OAuth Ligin | ||
|
|
||
| ## Authors | ||
|
|
||
| - [Travis Vachon](https://github.com/travis), [Storacha Network](https://storacha.network) | ||
|
|
||
| ## Introduction | ||
|
|
||
| In order to upload data to the Storacha Network, users must first a) authenticate | ||
| and b) obtain a "storage plan." Originally, (b) required using the Stripe checkout | ||
| process to provide credit card information that could be used to charge for monthly | ||
| storage and overages, but in Q1 2025 we made it possible for users to sign up using | ||
| [GitHub OAuth](./oauth-login.md) which would simultaneously authenticate them (because | ||
| GitHub provides OAuth API access to a "verified" email address) and grant them | ||
| a basic storage plan with a 100MB data storage allocation. This helped decrease | ||
| the amount of friction in our signup process and provided a neat way to let people | ||
| use Storacha at hackathons and similar events - both big wins for a critical user | ||
| acquisition funnel for our service. | ||
|
|
||
| In this RFC we propose extending this pattern to the Bluesky OAuth flow - | ||
| [recent additions to Bluesky OAuth](https://docs.bsky.app/blog/oauth-improvements#email-transitional-scope) | ||
| mean that we determine when a Bluesky's email address has been verified by the PDS | ||
| and, assuming we trust the PDS, authenticate a user and grant them a basic storage | ||
| allocation the same way we do with GitHub. | ||
|
|
||
| ## Proposal | ||
|
|
||
| We propose implementing [OAuth Login](./oauth-login.md) for Bluesky OAuth. We'd like to | ||
| add a new OAuth endpoint using the same techniques that we do for GitHub today. The | ||
| primary difference between the existing GitHub OAuth callback and the new Bluesky OAuth | ||
| callback is that we'll use the Bluesky API client rather than the GitHub API client to | ||
| register and record OAuth access tokens. | ||
|
|
||
| Importantly, we will follow the same pattern proposed in [OAuth Login](./oauth-login.md) | ||
| to give users a small storage allocation if their Bluesky email is "verified". | ||
|
|
||
| An existing implementation of a Bluesky OAuth | ||
| callback, in use by our bsky.storage application, can be found here: | ||
|
|
||
| https://github.com/storacha/bluesky-backup-webapp-server/blob/main/src/app/atproto/callback/page.tsx | ||
|
|
||
| Additional infrastructure and changes to support this are considered below. | ||
|
|
||
| ### Session and State Stores | ||
|
|
||
| The ATProto (ie, Bluesky) OAuth client requires the implementation of two data stores: | ||
| one for OAuth state, used during OAuth signup, and one for OAuth sessions, used by our | ||
| backend to execute backups. An existing implementation of these stores using PostgreSQL | ||
| can be found here: | ||
|
|
||
| https://github.com/storacha/bluesky-backup-webapp-server/blob/5af6352bb4ac07e817975e3af43ebfed45fa7c8b/src/lib/server/db.ts#L98 | ||
|
|
||
| For this project we will reimplement these in DynamoDB - the shape of this API is a better match for DynamoDB's semantics than PostgreSQL so this should be straightforward. | ||
|
|
||
| ### Request Lock | ||
|
|
||
| Some operations provided by the ATProto OAuth client require a semaphore to avoid race conditions when interacting with the remote OAuth service. bsky.storage uses a SQL implementation of this interface that can be found here: | ||
|
|
||
| https://github.com/storacha/bluesky-backup-webapp-server/blob/5af6352bb4ac07e817975e3af43ebfed45fa7c8b/src/lib/server/db.ts#L183 | ||
|
|
||
| And implementation of this interface built on [`redlock`](https://www.npmjs.com/package/redlock) can be found in the documentation for the ATProto OAuth client library: | ||
|
|
||
| https://www.npmjs.com/package/@atproto/oauth-client-node | ||
|
|
||
| We propose using this on top of one of AWS's Redis-like services. | ||
|
|
||
| ### Client Metadata | ||
|
|
||
| The Bluesky OAuth process requires our server to expose two new endpoints to ensure | ||
| secure communication. The first exposes metadata about our OAuth implementation. An | ||
| implementation of this can be found here: | ||
|
|
||
| https://github.com/storacha/bluesky-backup-webapp-server/blob/5af6352bb4ac07e817975e3af43ebfed45fa7c8b/src/app/atproto/oauth-client-metadata/%5Baccount%5D/route.ts | ||
|
|
||
| Note that passing `account` to the metadata function is not strictly required, and we expect to be able to get rid of this requirement in the new implementation. | ||
|
|
||
| ### JWKS | ||
|
|
||
| Similar to `Client Metadata` above, the server must expose an endpoint that lists its JWK | ||
| public keys to facilitate secure communication between our server and the OAuth server. | ||
| The existing implementation can be found here: | ||
|
|
||
| https://github.com/storacha/bluesky-backup-webapp-server/blob/5af6352bb4ac07e817975e3af43ebfed45fa7c8b/src/app/atproto/oauth/jwks/route.ts | ||
|
|
||
|
|
||
| ### Access to Access Tokens | ||
|
|
||
| The existing bsky.storage service needs access to at least the session store (and | ||
| possible the state store) in order to back up user data. There are two main options for | ||
| this: | ||
|
|
||
| 1) We could add additional UCAN invocations that let bsky.storage get the data it needs from our backends | ||
| 2) We could give bsky.storage access to the DynamoDB tables it needs | ||
|
|
||
| While (1) is probably more "correct" and in line with the way we build systems, (2) is | ||
| probably significantly less work and aligns with this being an internal application | ||
| rather than a third party integration. We therefore propose going with (2) which will | ||
| require adjusting the bsky.storage Storoku configuration to give that backend service | ||
| access to the DynamoDB tables it needs. | ||
|
|
||
| ## Work Plan | ||
|
|
||
| 1) Finish implementation of OAuth callback | ||
| 2) Finish implementation of supporting endpoints (JWKs, client metadata) | ||
| 3) Implement session and state stores in terms of Dynamo | ||
| 4) Implement Request Lock using an AWS Redis-like service | ||
| 5) Update bsky.storage's deployment configuration to give it access to the necessary Dynamo tables | ||
| 6) Update bsky.storage to use the Dynamo-backed implementations of the session and state stores | ||
|
|
||
| ## Draft Implementation | ||
|
|
||
| We have used Claude to create a rough sketch of the new OAuth callback - it is neither | ||
| bug-free nor complete, but should help give more context and detail to the proposal | ||
| above: | ||
|
|
||
| https://github.com/storacha/w3infra/pull/505 | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.