0.2.15 • Published 3 months ago

bluesky-oauth-kit v0.2.15

Weekly downloads
-
License
ISC
Repository
github
Last release
3 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

3 months ago

0.2.14

3 months ago

0.2.13

3 months ago

0.2.12

3 months ago

0.2.11

3 months ago

0.2.10

3 months ago

0.2.9

3 months ago

0.2.8

3 months ago

0.2.7

4 months ago

0.2.6

4 months ago

0.2.5

4 months ago

0.2.4

4 months ago

0.2.3

4 months ago