Skip to content

Summpot/BeaconAuth

Repository files navigation

BeaconAuth

BeaconAuth is a modern, secure authentication system for Minecraft servers, featuring a web-based login interface with OAuth support and a companion mod for seamless in-game authentication.

Build Release License

Features

Authentication Server

  • 🔐 ES256 JWT Authentication - Industry-standard elliptic curve cryptography
  • 🌐 Modern Web Interface - React-based login and registration pages
  • 🍪 Session Management - Secure HttpOnly cookies with refresh token rotation
  • 🔑 OAuth Integration - Support for GitHub, Google, and Microsoft authentication
  • 🔒 WebAuthn/Passkey Support - Passwordless authentication with biometrics
  • 🗄️ SQLite Database - Simple, file-based user storage
  • 🐳 Docker Ready - Multi-architecture container images (amd64/arm64)
  • Edge + server ready - Built with TypeScript (Nitro + Elysia)

Minecraft Mod

  • 🎮 Automatic Login Flow - Seamless in-game authentication
  • 🔒 PKCE Security - Proof Key for Code Exchange protection
  • 🌍 Multi-Loader Support - Works with both Fabric and Forge
  • 🌐 Internationalization - English and Chinese translations
  • ⚙️ Configurable - Server-side TOML configuration
  • 🔗 JWT Validation - Secure verification using JWKS

Table of Contents

Quick Start

Using Docker (Recommended)

The easiest way to deploy BeaconAuth is using Docker:

# Pull the latest image
docker pull ghcr.io/summpot/beacon_auth:latest

# Run the server
docker run -d --name beaconauth \
  -p 8080:8080 \
  -v $(pwd)/data:/app/data \
  -e DATABASE_URL=sqlite:///app/data/beacon_auth.db \
  ghcr.io/summpot/beacon_auth:latest

The server will be available at http://localhost:8080.

Building from Source

Prerequisites

  • Node.js 22 or later
  • pnpm 10 or later
  • (Optional) Java 21+ if you also want to build the Minecraft mod locally

Build Steps

# Clone the repository
git clone https://github.com/Summpot/beacon_auth.git
cd beacon_auth

# Install frontend dependencies
pnpm install

# Generate routes + build
pnpm routes
pnpm build

Cloudflare Deployment (Pages)

This repository ships a Cloudflare Pages deployment (including Pages Functions via Nitro) so the browser stays on a single origin.

To avoid cross-origin headaches, the Pages deployment includes a small dist/_worker.js that proxies these paths to the API Worker:

  • /api/*
  • /v1/*
  • /.well-known/*

Everything else (SPA routes like /login) is served as static content from Pages.

Wrangler config

This repo uses a single Wrangler config at the repo root:

  • wrangler.jsonc: Cloudflare Pages (static output in dist/)

GitHub Actions deployment

Workflow:

  • .github/workflows/deploy-cloudflare.yml

Required GitHub Actions secrets:

Secret Required Used for
CLOUDFLARE_API_TOKEN Yes Wrangler authentication (deploy)
CLOUDFLARE_ACCOUNT_ID Yes Pin the Cloudflare Account ID in CI so Wrangler does not need to infer it via /memberships

The workflow will:

  • generate routes
  • build the app
  • deploy Cloudflare Pages from dist/

The workflow runs on pushes to main and can also be triggered manually.

Auth Server Deployment

Configuration

BeaconAuth is configured via environment variables.

Key environment variables

Variable Required Default Description
BASE_URL No http://localhost:3000 Public base URL used for issuer + OAuth redirects + WebAuthn RP origin
DATABASE_URL No - Enables password-based auth when set (e.g. sqlite:///app/data/beacon_auth.db)
DATABASE_AUTH_TOKEN No - Optional auth token for remote DB providers
JWT_PRIVATE_JWK Yes - ES256 private key in JSON JWK format (used to sign tokens)
JWT_KID No beaconauth JWT key id
JWT_ISSUER No BASE_URL JWT issuer
JWKS_URL No ${BASE_URL}/.well-known/jwks.json JWKS URL for jku header
JWT_EXPIRATION No 120 Legacy default for JWT exp (seconds)
ACCESS_TOKEN_EXPIRATION No 900 Access token exp (seconds)
REFRESH_TOKEN_EXPIRATION No 2592000 Refresh token exp (seconds)
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET No - GitHub OAuth
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET No - Google OAuth
MICROSOFT_CLIENT_ID / MICROSOFT_CLIENT_SECRET No - Microsoft OAuth
MICROSOFT_TENANT No common Microsoft tenant (common, organizations, consumers, or a tenant GUID)

Example Configuration

Create a .env file in your working directory:

DATABASE_URL=sqlite:///app/data/beacon_auth.db
BIND_ADDRESS=0.0.0.0:8080
JWT_EXPIRATION=7200
CORS_ORIGINS=http://localhost:3000

# Optional: OAuth providers
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
MICROSOFT_CLIENT_ID=your_microsoft_client_id
MICROSOFT_CLIENT_SECRET=your_microsoft_client_secret
# Optional; defaults to "common". Use a tenant GUID to restrict logins to a single tenant.
MICROSOFT_TENANT=common
BASE_URL=https://auth.example.com

Database Setup

BeaconAuth uses SQLite by default. Initialize the database with:

# Run migrations
beacon migrate --database-url sqlite://./beacon_auth.db

# Create an initial admin user
beacon create-user --username admin --password your_secure_password

# List all users
beacon list-users

# Delete a user
beacon delete-user --username username

OAuth Setup

GitHub OAuth

  1. Go to GitHub Developer Settings
  2. Click "New OAuth App"
  3. Fill in the details:
    • Application name: BeaconAuth
    • Homepage URL: https://beaconauth.pages.dev (or your domain)
    • Authorization callback URL: https://beaconauth.pages.dev/api/v1/oauth/callback
  4. Copy the Client ID and Client Secret
  5. Set environment variables:
    export GITHUB_CLIENT_ID=your_client_id
    export GITHUB_CLIENT_SECRET=your_client_secret

Google OAuth

  1. Go to Google Cloud Console
  2. Create a new project or select an existing one
  3. Enable the Google+ API
  4. Go to CredentialsCreate CredentialsOAuth Client ID
  5. Configure the OAuth consent screen
  6. Create credentials:
    • Application type: Web application
    • Authorized redirect URIs: https://beaconauth.pages.dev/api/v1/oauth/callback
  7. Copy the Client ID and Client Secret
  8. Set environment variables:
    export GOOGLE_CLIENT_ID=your_client_id
    export GOOGLE_CLIENT_SECRET=your_client_secret

Microsoft OAuth

BeaconAuth uses the Microsoft identity platform (v2.0) and Microsoft Graph to fetch the signed-in user's profile.

  1. Go to the Azure Portal → Microsoft Entra IDApp registrations
  2. Click New registration
  3. Fill in the details:
  • Name: BeaconAuth
  • Supported account types: choose what fits your deployment
  1. After creation, note:
  • Application (client) IDMICROSOFT_CLIENT_ID
  • (Optional) Directory (tenant) ID (if you want to restrict to one tenant)
  1. Configure a redirect URI:
  • Go to AuthenticationAdd a platformWeb
  • Add Redirect URI: https://beaconauth.pages.dev/api/v1/oauth/callback (or your own ${BASE_URL}/api/v1/oauth/callback)
  1. Create a client secret:
  • Go to Certificates & secretsNew client secret
  • Copy the value → MICROSOFT_CLIENT_SECRET
  1. Ensure API permissions include Microsoft Graph User.Read (delegated)
  2. Set environment variables:
export MICROSOFT_CLIENT_ID=your_client_id
export MICROSOFT_CLIENT_SECRET=your_client_secret
# Optional; defaults to "common".
export MICROSOFT_TENANT=common

Production Deployment

Using Docker Compose

Create a docker-compose.yml:

version: '3.8'

services:
  beaconauth:
    image: ghcr.io/summpot/beacon_auth:latest
    ports:
      - "8080:8080"
    volumes:
      - ./data:/app/data
    environment:
      DATABASE_URL: sqlite:///app/data/beacon_auth.db
      BIND_ADDRESS: 0.0.0.0:8080
      JWT_EXPIRATION: 7200
      GITHUB_CLIENT_ID: ${GITHUB_CLIENT_ID}
      GITHUB_CLIENT_SECRET: ${GITHUB_CLIENT_SECRET}
      GOOGLE_CLIENT_ID: ${GOOGLE_CLIENT_ID}
      GOOGLE_CLIENT_SECRET: ${GOOGLE_CLIENT_SECRET}
      MICROSOFT_CLIENT_ID: ${MICROSOFT_CLIENT_ID}
      MICROSOFT_CLIENT_SECRET: ${MICROSOFT_CLIENT_SECRET}
      MICROSOFT_TENANT: ${MICROSOFT_TENANT}
      BASE_URL: https://auth.example.com
    restart: unless-stopped

Start the service:

docker-compose up -d

Reverse Proxy Configuration (Nginx)

server {
    listen 80;
    server_name auth.example.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

For HTTPS, use Let's Encrypt:

certbot --nginx -d auth.example.com

Mod Installation

Server Installation

  1. Download the Mod: Get the latest mod file from the Releases page

    • For Fabric: beaconauth-fabric-1.0.0.jar
    • For Forge: beaconauth-forge-1.0.0.jar
  2. Install the Mod:

    • Place the jar file in your server's mods/ directory
    • Restart the server
  3. Configure the Mod: Edit config/beaconauth-server.toml (see Mod Configuration)

Client Installation

  1. Download the Mod: Same mod file as the server version

  2. Install the Mod:

    • Place the jar file in your client's mods/ directory
    • The mod will automatically handle the client-side authentication flow
  3. Requirements:

  • Fabric / Forge / NeoForge (pick the correct jar for your loader)
  • Supported Minecraft versions: 1.20.1, 1.21.1, 1.21.8

Mod Configuration

After the first server startup, a configuration file will be generated at config/beaconauth-server.toml:

# BeaconAuth Server Configuration

[authentication]
# Base URL of your authentication server
# Example: https://beaconauth.pages.dev (development) or https://auth.example.com (production)
# WARNING: Always use HTTPS in production!
base_url = "https://beaconauth.pages.dev"

# JWKS (JSON Web Key Set) URL for JWT signature verification (fallback)
# Usually: <base_url>/.well-known/jwks.json
# Empty means: derive from base_url
jwks_url = ""

[jwt]
# Expected JWT audience (aud claim)
audience = "minecraft-client"

[jku]
# JWT JWKS Discovery (JKU)
# If allowed_host_patterns is non-empty and the JWT has a 'jku' header, BeaconAuth will fetch keys from that JWKS URL.
# Security: You MUST restrict allowed hosts to avoid SSRF.
# When enabled, JKU ALWAYS requires https://.
# Empty means: JKU disabled (BeaconAuth will ignore token 'jku' and only use authentication.jwks_url).
allowed_host_patterns = "beaconauth.pages.dev, *.beaconauth.pages.dev"

[behavior]
# If true: Players with valid Mojang accounts skip BeaconAuth when server is in online-mode
bypass_if_online_mode_verified = true
# If true: Modded clients MUST authenticate when server is offline-mode
force_auth_if_offline_mode = true
# Only applies when force_auth_if_offline_mode is true
allow_vanilla_offline_clients = false

Notes

  • authentication.base_url is used for:
    • building the web login URL
    • the expected JWT issuer (iss) (derived from base_url) Make sure it matches your auth server's configured BASE_URL.
  • authentication.jwks_url is the fallback JWKS endpoint. If empty, BeaconAuth derives it as ${base_url}/.well-known/jwks.json.
  • jku.allowed_host_patterns controls whether BeaconAuth will trust a JWT header jku:
    • non-empty: JKU enabled and must be https://
    • empty: JKU disabled, token jku is ignored
    • patterns are comma/space-separated
    • supported: example.com, *.example.com (both match the base domain and subdomains)
    • not supported: bare * or mid-string wildcards like auth*.example.com

For production deployments:

[authentication]
base_url = "https://auth.example.com"
jwks_url = ""

[jwt]
audience = "minecraft-client"

[jku]
allowed_host_patterns = "auth.example.com, *.auth.example.com"

Development Guide

Project Structure

This is a monorepo containing two primary deliverables:

  • Web app (UI + API) built with TypeScript (TanStack Start + Nitro + Elysia)
  • Minecraft mod built with Gradle/Kotlin
beacon_auth/
├── src/                         # Web app (React + server)
│   ├── routes/                  # TanStack Router pages
│   │   ├── index.tsx            # Login page
│   │   ├── register.tsx         # Registration page
│   │   └── ...
│   ├── server/                  # API/auth implementation (Nitro + Elysia)
│   └── ...
├── modSrc/                      # Minecraft Mod (Kotlin/Gradle)
│   ├── common/                  # Shared code
│   │   └── src/main/kotlin/
│   │       ├── client/          # Client-side code
│   │       │   ├── AuthClient.kt
│   │       │   └── ...
│   │       ├── server/          # Server-side code
│   │       │   ├── AuthServer.kt
│   │       │   └── ...
│   │       ├── network/         # Network packets
│   │       ├── config/          # Configuration
│   │       └── ...
│   ├── fabric/                  # Fabric implementation
│   └── forge/                   # Forge implementation
├── .github/workflows/           # CI/CD workflows
├── Dockerfile                   # Docker image definition
├── wrangler.jsonc               # Cloudflare Pages config
└── package.json                 # Web dependencies

Development Setup

Auth Server Development

  1. Install dependencies:

Install web dependencies

pnpm install


2. **Run in development mode**:
```bash
pnpm dev
  1. Access the application:
  • Dev server: follow the URL printed by the dev command

Mod Development

  1. Open in IDE:

    • IntelliJ IDEA: Open modSrc/build.gradle.kts
    • Eclipse: Import as Gradle project
  2. Build the mod:

    cd modSrc
    ./gradlew build
  3. Run development server:

    # Fabric
    ./gradlew :fabric:runServer
    
    # Forge
    ./gradlew :forge:runServer
  4. Run development client:

    # Fabric
    ./gradlew :fabric:runClient
    
    # Forge
    ./gradlew :forge:runClient

Building Components

Build web app (static output)

pnpm routes
pnpm build

Output will be in dist/.

Build Docker image

docker build -t beaconauth:local .

Build Mod

cd modSrc

# Build all loaders
./gradlew build

# Build specific loader
./gradlew :fabric:build
./gradlew :forge:build

Artifacts:

  • Fabric: modSrc/fabric/build/libs/beaconauth-fabric-*.jar
  • Forge: modSrc/forge/build/libs/beaconauth-forge-*.jar

Testing

Auth Server Tests

# Generate routes and run static checks
pnpm routes
pnpm check

# Build
pnpm build

There is no separate unit test suite configured yet; CI currently relies on Biome checks + build.

Mod Tests

cd modSrc
./gradlew test

API Documentation

Authentication Endpoints

POST /api/v1/login

Authenticate a user with username and password. Sets HttpOnly session cookies.

Request:

{
  "username": "player123",
  "password": "secure_password"
}

Response (200 OK):

{
  "success": true
}

Cookies Set:

  • access_token - ES256 JWT valid for 15 minutes
  • refresh_token - Random token valid for 7 days

POST /api/v1/register

Register a new user account. Auto-logs in the user by setting session cookies.

Request:

{
  "username": "newplayer",
  "password": "secure_password"
}

Response (201 Created):

{
  "success": true
}

Cookies Set:

  • access_token - ES256 JWT valid for 15 minutes
  • refresh_token - Random token valid for 7 days

POST /api/v1/refresh

Refresh an expired access token using a valid refresh token.

Request: Requires refresh_token cookie

Response (200 OK):

{
  "success": true
}

Cookies Set:

  • access_token - New ES256 JWT valid for 15 minutes

POST /api/v1/minecraft-jwt

Generate a Minecraft-specific JWT for mod authentication. Requires valid session.

Request:

{
  "challenge": "PKCE_challenge_string",
  "redirect_port": 38125
}

Response (200 OK):

{
  "redirectUrl": "http://localhost:38125/auth-callback?jwt=eyJ..."
}

POST /api/v1/oauth/start

Initiate OAuth authentication flow.

Request:

{
  "provider": "github",
  "challenge": "PKCE_challenge_string",
  "redirect_port": 38125
}

Response (200 OK):

{
  "authorizationUrl": "https://github.com/login/oauth/authorize?..."
}

GET /api/v1/oauth/callback

OAuth provider callback endpoint.

Query Parameters:

  • code: Authorization code from OAuth provider
  • state: State token for validation

Response: HTTP 302 redirect to mod callback URL with JWT

Public Endpoints

GET /.well-known/jwks.json

Retrieve JSON Web Key Set for JWT verification.

Response (200 OK):

{
  "keys": [
    {
      "kty": "EC",
      "use": "sig",
      "crv": "P-256",
      "kid": "beacon-auth-key-1",
      "x": "...",
      "y": "...",
      "alg": "ES256"
    }
  ]
}

Troubleshooting

Common Issues

Server won't start

Problem: Database connection error

Solution:

# Ensure database directory exists
mkdir -p data

# Run migrations
beacon migrate --database-url sqlite://./data/beacon_auth.db

Frontend build fails in Docker

Problem: pnpm: command not found

Solution: The build.rs script automatically handles frontend builds. Ensure pnpm is installed in your system PATH.

Mod authentication fails

Problem: "Failed to validate JWT"

Solutions:

  1. Check authentication.base_url in config/beaconauth-server.toml matches your deployed auth server (BASE_URL)
  2. Check authentication.jwks_url:
  • if empty, BeaconAuth uses ${authentication.base_url}/.well-known/jwks.json
  • if set, ensure it is reachable from the game server
  1. If you enabled JKU (non-empty jku.allowed_host_patterns):
  • the token jku must be https://...
  • the jku host must match your allowlist patterns (to prevent SSRF)
  1. Verify the auth server is accessible from the Minecraft server/client network
  2. Check Minecraft server logs for [BeaconAuth] and JWT verification errors

Multiplayer chat cannot be sent (secure chat)

Minecraft 1.19+ uses signed chat. BeaconAuth accounts are not Mojang accounts, so they do not have the normal chat signing keys.

On supported builds, BeaconAuth will send unsigned chat packets for BeaconAuth-authenticated sessions to improve compatibility.

Additionally, when installed on a dedicated server, BeaconAuth disables vanilla "secure profile" enforcement (the enforce-secure-profile check), because BeaconAuth-authenticated players do not have Mojang-signed profile public keys.

If you still cannot chat, double-check that the BeaconAuth mod is present on both client and server for that Minecraft version.

Username shown in-game is not the BeaconAuth username

BeaconAuth can provide a separate Minecraft username via the JWT claim username.

If present and valid (3..16 chars, [A-Za-z0-9_]), the server will use it as the in-game GameProfile name (tab list / chat name). If it is missing or invalid, BeaconAuth falls back to the launcher-provided username.

OAuth redirect fails

Problem: "Invalid redirect URI"

Solutions:

  1. Verify OAuth app callback URL matches exactly: http://yourserver:8080/api/v1/oauth/callback
  2. Check BASE_URL environment variable
  3. For production, use HTTPS and proper domain

Debug Logging

Enable detailed logging:

Auth Server:

# Local dev
pnpm dev

# Or build + run the Node server output
pnpm routes
pnpm build
pnpm start

Mod (server log): Look for [BeaconAuth] prefix in server logs.

Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Run checks/tests (pnpm routes && pnpm check && pnpm build && cd modSrc && ./gradlew test)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

Code Style

  • TypeScript: Use Biome (pnpm check / pnpm check:fix)
  • Kotlin: Follow Kotlin conventions (configured in .editorconfig)

Commit Messages

Use conventional commit format:

  • feat: New features
  • fix: Bug fixes
  • docs: Documentation changes
  • chore: Maintenance tasks
  • test: Test additions or modifications

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Support


Made with ❤️ by Summpot

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages