# 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`<br>`rpc-ws-prv.d-bis.org` | ✅ JWT Required | 192.168.11.251 |
| 2502 | Public RPC | `rpc-http-pub.d-bis.org`<br>`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 <token>` 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 <token>" 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

