generated from bleumoon/template
A comprehensive Client/Server OAuth2 library for Bleumoon.
- Luau 99.1%
- Nix 0.9%
BleuMoon's init.luau parent-directory context resolution causes @src
aliases in root init.luau to resolve against the parent directory's
.luaurc instead of the package's own .luaurc. This makes @src point to
the consumer project's src/ instead of the package's src/.
Fix: move all entry logic to src/init.luau where the parent-directory
context resolves to the package root (which has the correct .luaurc).
Root init.luau becomes a thin proxy: require("./bleuauth/src").
|
||
|---|---|---|
| .forgejo/workflows | ||
| .github | ||
| .vscode | ||
| docs | ||
| src | ||
| tests | ||
| .editorconfig | ||
| .gitignore | ||
| .luaurc | ||
| bleumoon.lock | ||
| bleumoon.toml | ||
| CHANGELOG.md | ||
| flake.lock | ||
| flake.nix | ||
| init.luau | ||
| LICENSE | ||
| README.md | ||
| stylua.toml | ||
BleuAuth
A comprehensive OAuth2 Client/Server library for BleuMoon — the standalone Luau runtime.
Features
- OAuth2 Server — Authorization endpoint, token endpoint, introspection (RFC 7662), revocation (RFC 7009), and discovery (RFC 8414)
- OAuth2 Client — Authorization Code (with PKCE), Client Credentials, and Refresh Token grants
- Resource Server Middleware — Bearer token validation via JWT verification and token introspection
- JWT — Encode, decode, and verify JWTs (RFC 7519/7515/7518) with HMAC (HS256/384/512) and asymmetric (RS256/ES256/EdDSA) algorithms
- JWK/JWKS — Key pair generation and JSON Web Key Set endpoints (RFC 7517)
- PKCE — Proof Key for Code Exchange (RFC 7636) with S256 method, required by default (OAuth 2.1)
- Pluggable Storage — In-memory (testing) and SQLite (production) storage backends
Prerequisites
Tip: If you have Nix with flakes enabled, both tools are provided automatically via
nix develop.
Quick Start
local bleuauth = require("./src")
-- Create an in-memory storage backend
local storage = bleuauth.createMemoryStorage()
-- Generate an RSA key pair for JWT signing
local keys = bleuauth.generateKeyPair("RS256")
-- Register a client
storage:createClient({
clientId = "my-app",
clientSecret = "secret",
redirectUris = { "https://myapp.example.com/callback" },
grantTypes = { "authorization_code", "client_credentials" },
scopes = { "read", "write" },
clientType = "confidential",
createdAt = os.time(),
})
-- Create and start the OAuth2 server
local server = bleuauth.createServer({
issuer = "https://auth.example.com",
storage = storage,
signingKey = keys.privateKey,
signingAlgorithm = "RS256",
signingKid = keys.kid,
publicKey = keys.publicKey,
supportedScopes = { "read", "write" },
authenticateUser = function(request, clientId, scope)
-- Your user authentication logic here
return "user-id-123"
end,
})
server:start(8080)
Architecture
src/
├── init.luau # Library entry point (exports everything)
├── types/init.luau # All shared type definitions
├── utils/
│ ├── init.luau # Utility re-exports
│ ├── pkce.luau # PKCE utilities (RFC 7636)
│ └── errors.luau # OAuth2 error builders (RFC 6749 §5.2)
├── jwt/
│ ├── init.luau # JWT encode/decode/verify
│ ├── algorithms.luau # Algorithm implementations
│ └── jwk.luau # JWK/JWKS key management
├── server/
│ ├── init.luau # Server factory with HTTP binding
│ ├── config.luau # Configuration defaults & validation
│ ├── authorize.luau # Authorization endpoint (GET /authorize)
│ ├── token.luau # Token endpoint (POST /token)
│ ├── introspect.luau # Introspection endpoint (POST /introspect)
│ ├── revoke.luau # Revocation endpoint (POST /revoke)
│ └── discovery.luau # Metadata & JWKS endpoints
├── client/init.luau # OAuth2 client implementation
├── middleware/init.luau # Resource server middleware
└── storage/
├── init.luau # Storage re-exports
├── memory.luau # In-memory storage (testing)
└── sqlite.luau # SQLite storage (production)
Note: Base64url encoding and URL/form encoding utilities live in the
bleuutilspackage and are re-exported from there.
Supported Grant Types
| Grant Type | RFC | Description |
|---|---|---|
| Authorization Code | RFC 6749 §4.1 | For server-side web apps (with mandatory PKCE) |
| Client Credentials | RFC 6749 §4.4 | For machine-to-machine communication |
| Refresh Token | RFC 6749 §6 | For obtaining new access tokens |
Note: Implicit grant and ROPC are intentionally omitted per OAuth 2.1 recommendations.
JWT Algorithms
| Algorithm | Type | Status |
|---|---|---|
| HS256 / HS384 / HS512 | HMAC | ✅ Fully working |
| RS256 | RSA-SHA256 | ✅ Fully working |
| ES256 | ECDSA P-256 | ✅ Fully working |
| EdDSA | Ed25519 | ✅ Fully working |
Running Tests
bleumoon run tests/init
Formatting
stylua --check . # Check
stylua . # Apply
Known Issues
crypto.randomBuffer()returns a string (not a buffer type) in BleuMoon v2.0.x. BleuAuth usescrypto.randomBytes()instead.
License
This project is licensed under the MIT License.