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.
- 🔐 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)
- ⚡ High Performance - Built with Rust and Actix-web
- 🎮 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
- Quick Start
- Cloudflare Deployment (Workers + Pages)
- Auth Server Deployment
- Mod Installation
- Development Guide
- API Documentation
- Troubleshooting
- Contributing
- License
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:latestThe server will be available at http://localhost:8080.
Download the latest release for your platform from the Releases page:
Linux (amd64):
wget https://github.com/Summpot/beacon_auth/releases/latest/download/beaconauth-linux-amd64-musl-v1.0.0.tar.gz
tar -xzf beaconauth-linux-amd64-musl-v1.0.0.tar.gz
chmod +x beacon
./beacon serveWindows (amd64):
# Download and extract the zip file
# Run in PowerShell:
.\beacon.exe servemacOS (Apple Silicon):
wget https://github.com/Summpot/beacon_auth/releases/latest/download/beaconauth-macos-arm64-v1.0.0.tar.gz
tar -xzf beaconauth-macos-arm64-v1.0.0.tar.gz
chmod +x beacon
./beacon serve# Clone the repository
git clone https://github.com/Summpot/beacon_auth.git
cd beacon_auth
# Install frontend dependencies
pnpm install
# Build the project
cargo build --workspace --release
# The binary will be at target/release/beaconThis repository ships a Cloudflare deployment that keeps the browser on a single origin while still separating concerns:
- API Worker:
crates/beacon-worker(Rust/WASM) using D1 + Workers KV. - Frontend (React): deployed to Cloudflare Pages.
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.
This repo uses two Wrangler configs at the repo root:
wrangler.workers.jsonc: the API Worker (crates/beacon-worker, D1 + KV, Rust/WASM)wrangler.jsonc: Cloudflare Pages (static UI + a service bindingBACKENDpointing to the API Worker)
This repo is configured for Automatic provisioning:
- D1 binding:
DB(configured withdatabase_name, no hard-codeddatabase_id) - KV binding:
KV(no hard-coded namespace id)
Workflow:
.github/workflows/deploy-cloudflare.yml
Required GitHub Actions secrets:
| Secret | Required | Used for |
|---|---|---|
CLOUDFLARE_API_TOKEN |
Yes | Wrangler authentication (deploy + D1 operations + secrets) |
CLOUDFLARE_ACCOUNT_ID |
Yes | Pin the Cloudflare Account ID in CI so Wrangler does not need to infer it via /memberships |
Recommended / optional secrets:
| Secret | Required | Used for |
|---|---|---|
CLOUDFLARE_WORKER_BASE_URL |
Recommended | Sets BASE_URL for issuer + OAuth redirects + WebAuthn RP origin. If omitted, CI defaults to https://<workerName>.pages.dev. |
CLOUDFLARE_WORKER_GITHUB_CLIENT_ID |
Optional | GitHub OAuth |
CLOUDFLARE_WORKER_GITHUB_CLIENT_SECRET |
Optional | GitHub OAuth |
CLOUDFLARE_WORKER_GOOGLE_CLIENT_ID |
Optional | Google OAuth |
CLOUDFLARE_WORKER_GOOGLE_CLIENT_SECRET |
Optional | Google OAuth |
CLOUDFLARE_WORKER_MICROSOFT_CLIENT_ID |
Optional | Microsoft OAuth |
CLOUDFLARE_WORKER_MICROSOFT_CLIENT_SECRET |
Optional | Microsoft OAuth |
CLOUDFLARE_WORKER_MICROSOFT_TENANT |
Optional | Microsoft OAuth tenant (defaults to common) |
The workflow will:
- build the frontend (React)
- deploy the API Worker (Automatic provisioning will create/link D1 + KV if needed)
- apply D1 migrations via
wrangler d1 migrations apply(idempotent) - sync Worker secrets (when provided)
- deploy Pages from
dist/(which includesdist/_worker.jsbuilt fromsrc/pages/_worker.tsvia rsbuild)
The workflow runs on pushes to main and can also be triggered manually.
BeaconAuth can be configured using environment variables or command-line arguments. All configuration options can be viewed with:
beacon serve --help| Option | Environment Variable | Default | Description |
|---|---|---|---|
--bind-address |
BIND_ADDRESS |
127.0.0.1:8080 |
Server bind address |
--database-url |
DATABASE_URL |
sqlite://./beacon_auth.db?mode=rwc |
Database connection URL |
--jwt-expiration |
JWT_EXPIRATION |
3600 |
JWT expiration time in seconds |
--cors-origins |
CORS_ORIGINS |
http://localhost:3000,http://localhost:5173 |
Allowed CORS origins |
--github-client-id |
GITHUB_CLIENT_ID |
- | GitHub OAuth client ID |
--github-client-secret |
GITHUB_CLIENT_SECRET |
- | GitHub OAuth client secret |
--google-client-id |
GOOGLE_CLIENT_ID |
- | Google OAuth client ID |
--google-client-secret |
GOOGLE_CLIENT_SECRET |
- | Google OAuth client secret |
--microsoft-client-id |
MICROSOFT_CLIENT_ID |
- | Microsoft OAuth client ID |
--microsoft-client-secret |
MICROSOFT_CLIENT_SECRET |
- | Microsoft OAuth client secret |
--microsoft-tenant |
MICROSOFT_TENANT |
common |
Microsoft OAuth tenant (common, organizations, consumers, or a tenant GUID) |
--base-url |
BASE_URL |
https://beaconauth.pages.dev |
Base URL used for issuer + OAuth redirects + WebAuthn RP origin |
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.comBeaconAuth 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- Go to GitHub Developer Settings
- Click "New OAuth App"
- 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
- Copy the Client ID and Client Secret
- Set environment variables:
export GITHUB_CLIENT_ID=your_client_id export GITHUB_CLIENT_SECRET=your_client_secret
- Go to Google Cloud Console
- Create a new project or select an existing one
- Enable the Google+ API
- Go to Credentials → Create Credentials → OAuth Client ID
- Configure the OAuth consent screen
- Create credentials:
- Application type: Web application
- Authorized redirect URIs:
https://beaconauth.pages.dev/api/v1/oauth/callback
- Copy the Client ID and Client Secret
- Set environment variables:
export GOOGLE_CLIENT_ID=your_client_id export GOOGLE_CLIENT_SECRET=your_client_secret
BeaconAuth uses the Microsoft identity platform (v2.0) and Microsoft Graph to fetch the signed-in user's profile.
- Go to the Azure Portal → Microsoft Entra ID → App registrations
- Click New registration
- Fill in the details:
- Name: BeaconAuth
- Supported account types: choose what fits your deployment
- After creation, note:
- Application (client) ID →
MICROSOFT_CLIENT_ID - (Optional) Directory (tenant) ID (if you want to restrict to one tenant)
- Configure a redirect URI:
- Go to Authentication → Add a platform → Web
- Add Redirect URI:
https://beaconauth.pages.dev/api/v1/oauth/callback(or your own${BASE_URL}/api/v1/oauth/callback)
- Create a client secret:
- Go to Certificates & secrets → New client secret
- Copy the value →
MICROSOFT_CLIENT_SECRET
- Ensure API permissions include Microsoft Graph User.Read (delegated)
- Set environment variables:
export MICROSOFT_CLIENT_ID=your_client_id
export MICROSOFT_CLIENT_SECRET=your_client_secret
# Optional; defaults to "common".
export MICROSOFT_TENANT=commonCreate 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-stoppedStart the service:
docker-compose up -dserver {
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-
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
- For Fabric:
-
Install the Mod:
- Place the jar file in your server's
mods/directory - Restart the server
- Place the jar file in your server's
-
Configure the Mod: Edit
config/beaconauth-server.toml(see Mod Configuration)
-
Download the Mod: Same mod file as the server version
-
Install the Mod:
- Place the jar file in your client's
mods/directory - The mod will automatically handle the client-side authentication flow
- Place the jar file in your client's
-
Requirements:
- Fabric / Forge / NeoForge (pick the correct jar for your loader)
- Supported Minecraft versions: 1.20.1, 1.21.1, 1.21.8
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 = falseauthentication.base_urlis used for:- building the web login URL
- the expected JWT issuer (
iss) (derived frombase_url) Make sure it matches your auth server's configuredBASE_URL.
authentication.jwks_urlis the fallback JWKS endpoint. If empty, BeaconAuth derives it as${base_url}/.well-known/jwks.json.jku.allowed_host_patternscontrols whether BeaconAuth will trust a JWT headerjku:- non-empty: JKU enabled and must be https://
- empty: JKU disabled, token
jkuis 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 likeauth*.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"This is a monorepo containing three distinct projects:
beacon_auth/
├── crates/ # Rust workspace (Auth Server)
│ ├── beacon/ # Main server binary
│ │ ├── src/
│ │ │ ├── main.rs # CLI entry point
│ │ │ ├── server.rs # HTTP server setup
│ │ │ ├── handlers.rs # API handlers
│ │ │ ├── crypto.rs # JWT/ECDSA utilities
│ │ │ ├── config.rs # Configuration
│ │ │ └── ...
│ │ └── Cargo.toml
│ ├── beacon-frontend-embed/ # Frontend build + embedded dist/ assets
│ │ ├── build.rs # Frontend build script (pnpm build)
│ │ ├── src/lib.rs # rust-embed wrapper
│ │ └── Cargo.toml
│ ├── entity/ # Sea-ORM entities
│ └── migration/ # Database migrations
├── src/ # Frontend (React/Rsbuild)
│ ├── routes/ # TanStack Router pages
│ │ ├── index.tsx # Login page
│ │ ├── register.tsx # Registration page
│ │ └── ...
│ └── ...
├── 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
├── package.json # Frontend dependencies
└── Cargo.toml # Rust workspace definition
-
Install dependencies:
# Install Rust curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Install Node.js and pnpm curl -fsSL https://get.pnpm.io/install.sh | sh - # Install frontend dependencies pnpm install
-
Run in development mode:
# Terminal 1: Run frontend dev server pnpm dev # Terminal 2: Run backend cargo run --bin beacon serve
-
Access the application:
- Frontend dev server:
http://localhost:5173 - Backend API:
http://localhost:8080
- Frontend dev server:
-
Open in IDE:
- IntelliJ IDEA: Open
modSrc/build.gradle.kts - Eclipse: Import as Gradle project
- IntelliJ IDEA: Open
-
Build the mod:
cd modSrc ./gradlew build -
Run development server:
# Fabric ./gradlew :fabric:runServer # Forge ./gradlew :forge:runServer
-
Run development client:
# Fabric ./gradlew :fabric:runClient # Forge ./gradlew :forge:runClient
# Debug build
cargo build --workspace
# Release build (optimized)
cargo build --workspace --release
# Cross-compile for different targets
cargo install cargo-zigbuild
cargo zigbuild --target x86_64-unknown-linux-musl --releasepnpm buildOutput will be in dist/.
cd modSrc
# Build all loaders
./gradlew build
# Build specific loader
./gradlew :fabric:build
./gradlew :forge:buildArtifacts:
- Fabric:
modSrc/fabric/build/libs/beaconauth-fabric-*.jar - Forge:
modSrc/forge/build/libs/beaconauth-forge-*.jar
# Run all tests
cargo test --workspace
# Run specific package tests
cargo test -p beacon
cargo test -p entity
# Run with logging
RUST_LOG=debug cargo test --workspace -- --nocapturepnpm testcd modSrc
./gradlew testAuthenticate 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 minutesrefresh_token- Random token valid for 7 days
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 minutesrefresh_token- Random token valid for 7 days
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
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..."
}Initiate OAuth authentication flow.
Request:
{
"provider": "github",
"challenge": "PKCE_challenge_string",
"redirect_port": 38125
}Response (200 OK):
{
"authorizationUrl": "https://github.com/login/oauth/authorize?..."
}OAuth provider callback endpoint.
Query Parameters:
code: Authorization code from OAuth providerstate: State token for validation
Response: HTTP 302 redirect to mod callback URL with JWT
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"
}
]
}Problem: Database connection error
Solution:
# Ensure database directory exists
mkdir -p data
# Run migrations
beacon migrate --database-url sqlite://./data/beacon_auth.dbProblem: pnpm: command not found
Solution: The build.rs script automatically handles frontend builds. Ensure pnpm is installed in your system PATH.
Problem: "Failed to validate JWT"
Solutions:
- Check
authentication.base_urlinconfig/beaconauth-server.tomlmatches your deployed auth server (BASE_URL) - 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
- If you enabled JKU (non-empty
jku.allowed_host_patterns):
- the token
jkumust behttps://... - the
jkuhost must match your allowlist patterns (to prevent SSRF)
- Verify the auth server is accessible from the Minecraft server/client network
- Check Minecraft server logs for
[BeaconAuth]and JWT verification errors
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.
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.
Problem: "Invalid redirect URI"
Solutions:
- Verify OAuth app callback URL matches exactly:
http://yourserver:8080/api/v1/oauth/callback - Check
BASE_URLenvironment variable - For production, use HTTPS and proper domain
Enable detailed logging:
Auth Server:
RUST_LOG=debug beacon serveMod (server log):
Look for [BeaconAuth] prefix in server logs.
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Run tests (
cargo test --workspace && cd modSrc && ./gradlew test) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Rust: Follow standard Rust conventions (
cargo fmt,cargo clippy) - TypeScript: Use Biome formatter (
pnpm check) - Kotlin: Follow Kotlin conventions (configured in
.editorconfig)
Use conventional commit format:
feat:New featuresfix:Bug fixesdocs:Documentation changeschore:Maintenance taskstest:Test additions or modifications
This project is licensed under the MIT License - see the LICENSE file for details.
- Actix-web - Rust web framework
- Sea-ORM - Rust ORM
- Architectury - Multi-loader mod framework
- Nimbus JOSE+JWT - JWT library for Java
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with ❤️ by Summpot