0.2.15 • Published 11 months ago

bluesky-oauth-kit v0.2.15

Weekly downloads
-
License
ISC
Repository
github
Last release
11 months ago

Bluesky OAuth (2.0) Kit

A drop-in, ready-to-use, Bluesky OAuth login solution for Node.js and Javascript (any client).

Accelerate the migration of third-party Bluesky apps and integrations from insecure authentication methods (password stored in plaintext), to modern OAuth.

This package aims to adhere to OAuth 2.0 norms, while providing a simple to understand and ready-to-use Node.js backend that can be used with any sort of frontend client (Javascript, Vue, React, React Native, Ionic/Capacitor, Android, Swift, Electron, PWA, etc.)

Examples provided for Express (with hopefully more to come.) Testing an PRs welcome!

Installation

npm i -s bluesky-oauth-kit

Usage

See examples directory.

Express (Default Options)

const express = require('express');
const { setupExpressAuth } = require('bluesky-oauth-kit');

const app = express();

// Basic setup
await setupExpressAuth(app);

// With additional options
await setupExpressAuth(app, {
    baseUrl: 'http://localhost:5001',
    redirectUrl: '/dashboard',
    clientName: 'My OAuth App',
    // Optional: Custom storage implementations
    stateStore: customStateStore,
    sessionStore: customSessionStore
});

Express (composable)

const express = require('express');
const { initializeOAuth, authenticateToken, setupOauthRoutes } = require('bluesky-oauth-kit');

const app = express();

(async function() {
    const { client, sessionStore, stateStore } = await initializeOAuth(options);
    setupOauthRoutes(app, sessionStore);
})();

Framework Support

The library works with multiple frameworks:

  • Express (primary support)

Other frameworks can be supported by PR.

Environment Variables

# Required
OAUTH_JWT_SECRET=your-jwt-secret
OAUTH_BASE_URL=http://localhost:5001
OAUTH_PRIVATE_KEY_1=your-private-key-1
OAUTH_PRIVATE_KEY_2=your-private-key-2
OAUTH_PRIVATE_KEY_3=your-private-key-3

# Optional
OAUTH_CLIENT_NAME=My OAuth App
OAUTH_USE_COOKIES=true
OAUTH_REDIRECT_URL=/dashboard
NODE_ENV=development

Custom Storage

The library uses in-memory storage by default, but you can implement your own storage:

class CustomStore {
    async get(key) { /* ... */ }
    async set(key, value) { /* ... */ }
    async del(key) { /* ... */ }
}

// Redis example
class RedisStore {
    constructor(redis) {
        this.redis = redis;
    }
    async get(key) { return JSON.parse(await this.redis.get(key)); }
    async set(key, value) { await this.redis.set(key, JSON.stringify(value)); }
    async del(key) { await this.redis.del(key); }
}

Available Endpoints

The library sets up the following endpoints:

  • /login - Serves a login form (optional, can be disabled)
  • /oauth/login - Initiates the OAuth flow
  • /oauth/callback - Handles the OAuth callback
  • /oauth/userinfo - Returns info about the authenticated user
  • /oauth/revoke - Revokes the current session
  • /oauth/client-metadata.json - Serves OAuth client metadata
  • /oauth/jwks.json - Serves the JSON Web Key Set

Configuration

await setupExpressAuth(app, {
    baseUrl: 'http://localhost:5001',
    serveLoginPage: true,  // Set to false to disable built-in login page
    serveErrorPage: true,  // Set to false to disable built-in error page
    loginPageTitle: 'Login with Bluesky',  // Customize login page
    display: 'page',  // 'page', 'popup', or 'touch' for mobile
    maxAge: 48 * 60 * 60 * 1000,  // Cookie lifetime
    cookieDomain: '.yourdomain.com',
    cookiePath: '/',
    cookieSecret: 'your-secret',
    addHeaders: true,
    forceHTTPS: true,
    // ... other options
});

Development

Running the Example

  1. Clone the repository
  2. Install dependencies:
    npm install
  3. Copy .env.example to .env and fill in your values:
    cp .env.example .env
  4. Run the example:
    node examples/express.js

The example server will start on http://localhost:5001

Generating Keys

You can generate OAuth keys in two ways:

  1. Using npx (recommended):
npx bluesky-oauth-kit generate-oauth-keys
  1. After installing as a dependency:
npm run generate-keys

This will either create a new .env file or append OAuth keys to your existing one.

Authentication Flow

The library implements standard OAuth 2.0 authentication, providing:

  1. A JWT containing:

    • sub: The user's DID (standard OpenID Connect subject identifier)
    • did: The user's DID (AT Protocol identifier)
    • iss: The issuer ('bsky.social')
    • iat: Token issue timestamp
  2. The /oauth/userinfo endpoint returns this basic profile information.

Note: For richer profile data (handle, displayName, avatar, etc.), you'll need to: 1. Install @atproto/api 2. Use the session to create an Agent 3. Call agent.getProfile()

Example:

const { Agent } = require('@atproto/api');

// Get rich profile data
const agent = new Agent(session);
const profile = await agent.getProfile({ actor: agent.did });
console.log(profile.data);  // Contains handle, displayName, avatar, etc.

Security Configuration

The library includes several security features that can be configured:

Cookie Options

When using OAUTH_USE_COOKIES=true, you can configure cookie security:

await setupExpressAuth(app, {
    maxAge: 7 * 24 * 60 * 60 * 1000,  // Cookie lifetime (default 48h)
    cookieDomain: '.yourdomain.com',   // Cookie domain
    cookiePath: '/',                   // Cookie path
    cookieSecret: 'your-secret',       // Enable signed cookies
});

Security Headers

The library automatically sets security headers:

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • X-XSS-Protection: 1; mode=block

CORS

Configure CORS in your Express app:

app.use(cors({
    origin: process.env.OAUTH_BASE_URL,
    methods: ['GET', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization'],
}));

HTTPS

In production (NODE_ENV=production):

  • Cookies are automatically set as Secure
  • HTTP requests are redirected to HTTPS
  • Cookies use SameSite=Strict

Rate Limiting

The example includes rate limiting. You should include this (or something similar) in your app.

const rateLimit = require('express-rate-limit');
app.use(['/login', '/oauth/*'], rateLimit({
    windowMs: 15 * 60 * 1000,  // 15 minutes
    max: 100                    // Limit each IP to 100 requests per window
}));

Available Scopes

The Bluesky OAuth server supports these scopes:

  • atproto - Standard AT Protocol access
  • transition:generic - Generic transition scope
  • transition:chat.bsky - Chat transition scope (future use)

OAuth Implementation Details

This library implements the AT Protocol OAuth specification via @atproto/oauth-client-node:

  • Secure OAuth 2.0 flow with PAR, DPoP, and PKCE
  • Session management
  • Token handling and refresh
  • Framework integrations (Express)
  • Configurable storage backends

Using the Bluesky API (ATProto) with this package

This kit provides a helper function, getClient(), to retrieve your authenticated client instance, which can be passed to @atproto/api to make authenticated API requests.

See examples/express.js.

0.2.15

11 months ago

0.2.14

11 months ago

0.2.13

11 months ago

0.2.12

11 months ago

0.2.11

11 months ago

0.2.10

11 months ago

0.2.9

11 months ago

0.2.8

11 months ago

0.2.7

12 months ago

0.2.6

12 months ago

0.2.5

12 months ago

0.2.4

12 months ago

0.2.3

12 months ago