# JWT Authentication for Permissioned RPC Endpoints
**Last Updated:** 2025-12-24
**Status:** Active Configuration
---
## Overview
JWT (JSON Web Token) authentication has been configured for the Permissioned RPC endpoints to provide secure, token-based access control.
### Endpoints with JWT Authentication
- **HTTP RPC**: `https://rpc-http-prv.d-bis.org`
- **WebSocket RPC**: `wss://rpc-ws-prv.d-bis.org`
### Endpoints without Authentication (Public)
- **HTTP RPC**: `https://rpc-http-pub.d-bis.org`
- **WebSocket RPC**: `wss://rpc-ws-pub.d-bis.org`
---
## Architecture
### VMID Mappings
| VMID | Type | Domain | Authentication | IP |
|------|------|--------|----------------|-----|
| 2501 | Permissioned RPC | `rpc-http-prv.d-bis.org`
`rpc-ws-prv.d-bis.org` | ✅ JWT Required | 192.168.11.251 |
| 2502 | Public RPC | `rpc-http-pub.d-bis.org`
`rpc-ws-pub.d-bis.org` | ❌ No Auth | 192.168.11.252 |
### Request Flow with JWT
1. **Client** makes request to `https://rpc-http-prv.d-bis.org`
2. **Nginx** receives request and extracts JWT token from `Authorization: Bearer ` header
3. **Lua Script** validates JWT token using secret key
4. **If valid**: Request is proxied to Besu RPC (127.0.0.1:8545)
5. **If invalid**: Returns 401 Unauthorized with error message
---
## Setup
### 1. Configure JWT Authentication
Run the configuration script:
```bash
cd /home/intlc/projects/proxmox
./scripts/configure-nginx-jwt-auth.sh
```
This script will:
- Install required packages (nginx, lua, lua-resty-jwt)
- Generate JWT secret key
- Configure Nginx with JWT validation
- Set up both HTTP and WebSocket endpoints
### 2. Generate JWT Tokens
Use the token generation script:
```bash
# Generate token with default settings (username: rpc-user, expiry: 365 days)
./scripts/generate-jwt-token.sh
# Generate token with custom username and expiry
./scripts/generate-jwt-token.sh my-username 30 # 30 days expiry
```
The script will output:
- The JWT token
- Usage examples for testing
---
## Usage
### HTTP RPC with JWT
```bash
# Test with curl
curl -k \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \
https://rpc-http-prv.d-bis.org
```
### WebSocket RPC with JWT
For WebSocket connections, include the JWT token in the Authorization header during the initial HTTP upgrade request:
```javascript
// JavaScript example
const ws = new WebSocket('wss://rpc-ws-prv.d-bis.org', {
headers: {
'Authorization': 'Bearer YOUR_JWT_TOKEN'
}
});
```
### Using with MetaMask or dApps
Most Ethereum clients don't support custom headers. For these cases, you can:
1. **Use a proxy service** that adds the JWT token
2. **Use the public endpoint** (`rpc-http-pub.d-bis.org`) for read-only operations
3. **Implement custom authentication** in your dApp
---
## Token Management
### Token Structure
JWT tokens contain:
- **Header**: Algorithm (HS256) and type (JWT)
- **Payload**:
- `sub`: Username/subject
- `iat`: Issued at (timestamp)
- `exp`: Expiration (timestamp)
- **Signature**: HMAC-SHA256 signature using the secret key
### Token Expiry
Tokens expire after the specified number of days. To generate a new token:
```bash
./scripts/generate-jwt-token.sh username days
```
### Revoking Tokens
JWT tokens cannot be revoked individually without changing the secret key. To revoke all tokens:
1. Generate a new JWT secret on VMID 2501:
```bash
ssh root@192.168.11.10 "pct exec 2501 -- openssl rand -base64 32 > /etc/nginx/jwt_secret"
```
2. Restart Nginx:
```bash
ssh root@192.168.11.10 "pct exec 2501 -- systemctl restart nginx"
```
3. Generate new tokens for authorized users
---
## Security Considerations
### Secret Key Management
- **Location**: `/etc/nginx/jwt_secret` on VMID 2501
- **Permissions**: 600 (readable only by root)
- **Backup**: Store securely, do not commit to version control
### Best Practices
1. **Use strong secret keys**: The script generates 32-byte random keys
2. **Set appropriate expiry**: Don't create tokens with excessive expiry times
3. **Rotate secrets periodically**: Change the secret key and regenerate tokens
4. **Monitor access logs**: Check `/var/log/nginx/rpc-http-prv-access.log` for unauthorized attempts
5. **Use HTTPS only**: All endpoints use HTTPS (port 443)
### Rate Limiting
Consider adding rate limiting to prevent abuse:
```nginx
limit_req_zone $binary_remote_addr zone=jwt_limit:10m rate=10r/s;
location / {
limit_req zone=jwt_limit burst=20 nodelay;
# ... JWT validation ...
}
```
---
## Troubleshooting
### 401 Unauthorized
**Error**: `{"error": "Missing Authorization header"}`
**Solution**: Include the Authorization header:
```bash
curl -H "Authorization: Bearer YOUR_TOKEN" ...
```
**Error**: `{"error": "Invalid or expired token"}`
**Solution**:
- Check token is correct (no extra spaces)
- Verify token hasn't expired
- Generate a new token if needed
### 500 Internal Server Error
**Error**: `{"error": "Internal server error"}`
**Solution**:
- Check JWT secret exists: `pct exec 2501 -- cat /etc/nginx/jwt_secret`
- Check lua-resty-jwt is installed: `pct exec 2501 -- ls /usr/share/lua/5.1/resty/jwt.lua`
- Check Nginx error logs: `pct exec 2501 -- tail -f /var/log/nginx/rpc-http-prv-error.log`
### Token Validation Fails
1. **Verify secret key matches**:
```bash
# On VMID 2501
cat /etc/nginx/jwt_secret
```
2. **Regenerate token** using the same secret:
```bash
./scripts/generate-jwt-token.sh
```
3. **Check token format**: Should be three parts separated by dots: `header.payload.signature`
---
## Testing
### Test JWT Authentication
```bash
# 1. Generate a token
TOKEN=$(./scripts/generate-jwt-token.sh test-user 365 | grep -A 1 "Token:" | tail -1)
# 2. Test HTTP endpoint
curl -k \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \
https://rpc-http-prv.d-bis.org
# 3. Test without token (should fail)
curl -k \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_chainId","params":[],"id":1}' \
https://rpc-http-prv.d-bis.org
# Expected: {"error": "Missing Authorization header"}
```
### Test Health Endpoint (No Auth Required)
```bash
curl -k https://rpc-http-prv.d-bis.org/health
# Expected: healthy
```
---
## Related Documentation
- [RPC_DNS_CONFIGURATION.md](RPC_DNS_CONFIGURATION.md) - DNS setup
- [BESU_RPC_CONFIGURATION_FIXED.md](../05-network/BESU_RPC_CONFIGURATION_FIXED.md) - Besu RPC configuration
- [NGINX_ARCHITECTURE_RPC.md](../05-network/NGINX_ARCHITECTURE_RPC.md) - Nginx architecture
---
## Quick Reference
**Generate Token:**
```bash
./scripts/generate-jwt-token.sh [username] [days]
```
**Use Token:**
```bash
curl -H "Authorization: Bearer " https://rpc-http-prv.d-bis.org
```
**Check Secret:**
```bash
ssh root@192.168.11.10 "pct exec 2501 -- cat /etc/nginx/jwt_secret"
```
**View Logs:**
```bash
ssh root@192.168.11.10 "pct exec 2501 -- tail -f /var/log/nginx/rpc-http-prv-access.log"
```
---
**Last Updated**: 2025-12-24