79554470

Date: 2025-04-04 04:40:44
Score: 0.5
Natty:
Report link

I've been fighting my way through this same set of issues. I'm not all the way there yet, but here's a summary of what I've found so far. Depending on what language you use, there are some working examples out there. Two that helped me were: https://github.com/bluesky-social/cookbook/tree/main/python-oauth-web-app and https://pkg.go.dev/github.com/potproject/atproto-oauth2-go-example.

Implementing OAuth with Bluesky API: The Missing Manual

Overview

Authenticating with Bluesky using OAuth is significantly more complex than traditional OAuth implementations due to Bluesky's use of advanced security mechanisms like DPoP (Demonstrating Proof of Possession) and their multi-tiered API architecture. This guide outlines the key requirements and steps for successfully implementing OAuth authentication with Bluesky.

Authentication Architecture Understanding

Bluesky's API consists of two main components:

  1. Personal Data Server (PDS) - Stores user data and provides endpoints for interacting with a user's own content
  2. AppView API - Provides endpoints for viewing and interacting with other users' content

Important: OAuth tokens can only be used with PDS endpoints, not with AppView endpoints.

Key Requirements

1. OAuth Flow Requirements

2. DPoP Authentication

3. API Access Limitations

Implementation Steps

1. Client Registration

Create a client metadata JSON file available at a public HTTPS URL:

{
  "client_id": "https://your-app.com/.well-known/bluesky-oauth.json",
  "application_type": "web",
  "client_name": "Your App Name",
  "client_uri": "https://your-app.com",
  "dpop_bound_access_tokens": true,
  "require_pkce": true,
  "grant_types": [
    "authorization_code",
    "refresh_token"
  ],
  "redirect_uris": [
    "https://your-app.com/auth/bluesky/callback"
  ],
  "response_types": [
    "code"
  ],
  "scope": "atproto transition:generic transition:chat.bsky",
  "token_endpoint_auth_method": "none"
}

2. Authorization Request

  1. Generate a PKCE code verifier and challenge
  2. Redirect user to Bluesky's authorization URL with:
    • client_id (URL to your metadata JSON)
    • redirect_uri
    • response_type = "code"
    • scope = "atproto transition:generic transition:chat.bsky"
    • code_challenge and code_challenge_method = "S256"
    • state (security token)

3. Token Exchange with DPoP

  1. Generate a P-256 key pair for DPoP
  2. Create a DPoP token for the token exchange request with the token endpoint URL
  3. Exchange the authorization code for tokens:
    • grant_type = "authorization_code"
    • code = received code from authorization
    • redirect_uri = same as in authorization request
    • code_verifier = PKCE verifier from step 2
    • client_id = URL to your metadata JSON
  4. Include DPoP header with the DPoP token
  5. Handle DPoP nonce from the server response for subsequent requests

4. Making API Requests

  1. Generate a new DPoP token for each request
  2. Use Authorization: DPoP <access_token> in the header
  3. Include the DPoP token in the DPoP header
  4. Include the server-provided nonce in subsequent DPoP tokens
  5. Only use PDS endpoints (those starting with /xrpc/com.atproto.*)
  6. Handle responses properly, including new nonces

5. Profile Information Access

To get user profile info:

GET /xrpc/com.atproto.repo.getRecord?repo=<user-did>&collection=app.bsky.actor.profile&rkey=self

The response structure is complex, with nested objects:

{
  "uri": "at://did:plc:abc123/app.bsky.actor.profile/self",
  "cid": "bafyreiabc123...",
  "value": {
    "$type": "app.bsky.actor.profile",
    "displayName": "User Name",
    "description": "Bio text",
    "avatar": {
      "$type": "blob",
      "ref": {
        "$link": "bafkreiabc123..."
      },
      "mimeType": "image/jpeg",
      "size": 12345
    }
  }
}

Common Pitfalls and Solutions

  1. "Bad token scope" error:

    • Ensure you're using DPoP (not Bearer) in the Authorization header
    • Make sure your DPoP token is signed with ES256
    • Verify you're accessing PDS endpoints, not AppView endpoints
  2. DPoP nonce issues:

    • Always store and reuse the most recent nonce from the server
    • Create a new DPoP token for each request
    • Handle the nonce retry flow correctly
  3. Avatar image access:

    • Avatar URLs must be constructed from the response:

      <endpoint>/xrpc/com.atproto.sync.getBlob?did=<user-did>&cid=<avatar-cid>
      
  4. Handle retrieval:

    • The getSession endpoint doesn't work with OAuth
    • Extract handle from other responses or store it when initially retrieved

Limitations

The OAuth implementation in Bluesky currently has these limitations:

  1. OAuth tokens can only access PDS endpoints (not AppView endpoints)
  2. Some operations will require using other authentication methods
  3. OAuth implementation differs from typical OAuth flows by requiring DPoP

For full API access, you may need to implement a hybrid approach using both OAuth for PDS endpoints and other authentication methods for AppView endpoints.

Reasons:
  • Blacklisted phrase (1): This guide
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (1):
Posted by: Dan Ratner