-
Notifications
You must be signed in to change notification settings - Fork 1
Authentication
This guide covers authentication methods and API token management in PVE4J.
- API Tokens
- Creating API Tokens
- Using API Tokens
- Token Security
- Password Authentication
- Ticket Authentication
- Common Authentication Patterns
- Troubleshooting Authentication
API tokens are the recommended authentication method for PVE4J. They provide:
- Secure, token-based authentication
- Fine-grained permission control
- Easy revocation
- No password exposure
Proxmox API tokens follow this format:
USER@REALM!TOKENID=SECRET
Components:
-
USER- Username (e.g.,root,admin,automation) -
REALM- Authentication realm (e.g.,pam,pve) -
TOKENID- Token identifier (user-defined) -
SECRET- Token secret (UUID generated by Proxmox)
// Root user with PAM authentication
String token = "root@pam!automation=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
// Custom user with PVE realm
String token = "admin@pve!readonly=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy";
// Service account
String token = "backup@pam!backup-service=zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz";- Log in to Proxmox web interface
- Navigate to Datacenter → Permissions → API Tokens
- Click Add
- Fill in the form:
- User: Select the user
-
Token ID: Enter a descriptive name (e.g.,
automation,readonly) -
Privilege Separation:
- Checked: Token has same permissions as user
- Unchecked: Token has limited permissions (recommended)
- Expire: Set expiration (optional)
- Comment: Add description
- Click Add
- Important: Copy the displayed secret immediately (shown only once)
SSH into your Proxmox server:
# Create API token
pveum user token add root@pam automation --privsep 0
# The secret will be displayed - save it immediatelyAfter creating a token, assign appropriate permissions:
# Grant VM.Admin role to token for all VMs
pveum acl modify /vms -token 'root@pam!automation' -role PVEVMAdmin
# Grant read-only access to cluster
pveum acl modify / -token 'root@pam!readonly' -role PVEAuditorimport fr.freshperf.pve4j.Proxmox;
Proxmox proxmox = Proxmox.create(
"pve.example.com",
8006,
"root@pam!automation=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
);public class ProxmoxConfig {
public static Proxmox createClient() {
String host = System.getenv("PROXMOX_HOST");
int port = Integer.parseInt(System.getenv("PROXMOX_PORT"));
String token = System.getenv("PROXMOX_API_TOKEN");
return Proxmox.create(host, port, token);
}
}Set environment variables:
export PROXMOX_HOST=pve.example.com
export PROXMOX_PORT=8006
export PROXMOX_API_TOKEN=root@pam!automation=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxximport java.io.*;
import java.util.Properties;
public class ProxmoxConfig {
public static Proxmox createClientFromConfig(String configPath)
throws IOException {
Properties props = new Properties();
try (FileInputStream fis = new FileInputStream(configPath)) {
props.load(fis);
}
String host = props.getProperty("proxmox.host");
int port = Integer.parseInt(props.getProperty("proxmox.port"));
String token = props.getProperty("proxmox.token");
return Proxmox.create(host, port, token);
}
}Configuration file (proxmox.properties):
proxmox.host=pve.example.com
proxmox.port=8006
proxmox.token=root@pam!automation=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx// BAD - hardcoded token
Proxmox proxmox = Proxmox.create(
"pve.example.com", 8006,
"root@pam!app=12345678-1234-1234-1234-123456789abc"
);
// GOOD - from environment
Proxmox proxmox = Proxmox.create(
System.getenv("PROXMOX_HOST"),
Integer.parseInt(System.getenv("PROXMOX_PORT")),
System.getenv("PROXMOX_API_TOKEN")
);# Create limited token for specific operations
pveum user token add automation@pve readonly --privsep 1
# Grant only necessary permissions
pveum acl modify /vms -token 'automation@pve!readonly' -role PVEAuditorpublic class TokenRotation {
public void rotateToken() {
// 1. Create new token in Proxmox
// 2. Update configuration with new token
// 3. Test new token
// 4. Remove old token from Proxmox
}
}When creating tokens, set expiration dates for better security:
pveum user token add root@pam temp --expire "2025-12-31"Regularly audit which tokens are in use and revoke unused ones.
# Linux/Mac
export PROXMOX_API_TOKEN="root@pam!app=secret"
# Windows
set PROXMOX_API_TOKEN=root@pam!app=secretimport javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class SecureConfig {
public String decryptToken(String encryptedToken, String key)
throws Exception {
Cipher cipher = Cipher.getInstance("AES");
SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedToken));
return new String(decrypted);
}
}PVE4J supports username/password authentication through the createWithPassword() method. This creates a client that authenticates using a ticket obtained from the Proxmox API.
import fr.freshperf.pve4j.Proxmox;
import fr.freshperf.pve4j.SecurityConfig;
try {
// With default PAM realm and secure settings
Proxmox proxmox = Proxmox.createWithPassword(
"pve.example.com",
8006,
"root",
"your-password"
);
// Now you can use the client as normal
System.out.println("Version: " + proxmox.getVersion().execute().getVersion());
} catch (ProxmoxAPIError | InterruptedException e) {
System.err.println("Authentication failed: " + e.getMessage());
}try {
// Authenticate with a specific realm (e.g., LDAP, Active Directory)
Proxmox proxmox = Proxmox.createWithPassword(
"pve.example.com",
8006,
"admin",
"password",
"ldap", // Custom realm
SecurityConfig.secure()
);
} catch (ProxmoxAPIError | InterruptedException e) {
System.err.println("Authentication failed: " + e.getMessage());
}try {
// For development with self-signed certificates
Proxmox proxmox = Proxmox.createWithPassword(
"192.168.1.100",
8006,
"root",
"password",
SecurityConfig.insecure()
);
} catch (ProxmoxAPIError | InterruptedException e) {
System.err.println("Authentication failed: " + e.getMessage());
}- Tickets are short-lived (2 hours by default)
- The client stores the ticket and CSRF token for subsequent requests
- If the session expires, you need to create a new client
- API tokens are recommended for long-running applications
Recommendation: Use API tokens for automated applications and password authentication for interactive tools or short-lived scripts.
For more control over the authentication process, you can manually request a ticket:
import fr.freshperf.pve4j.entities.access.PveAccessTicket;
try {
PveAccessTicket ticket = proxmox.getAccess()
.getTicket("root", "password123", "pam")
.execute();
System.out.println("Ticket: " + ticket.getTicket());
System.out.println("CSRF Token: " + ticket.getCSRFPreventionToken());
System.out.println("Username: " + ticket.getUsername());
System.out.println("Cluster: " + ticket.getClustername());
} catch (ProxmoxAPIError | InterruptedException e) {
System.err.println("Authentication failed: " + e.getMessage());
}- Short-lived (2 hours by default)
- Requires password storage
- Needs refresh mechanism for long-running applications
public class ProxmoxClient {
private static final Proxmox INSTANCE;
static {
INSTANCE = Proxmox.create(
System.getenv("PROXMOX_HOST"),
Integer.parseInt(System.getenv("PROXMOX_PORT")),
System.getenv("PROXMOX_API_TOKEN")
);
}
public static Proxmox getInstance() {
return INSTANCE;
}
}public class ProxmoxOperations {
public void performOperation() {
Proxmox proxmox = createClient();
try {
// Perform operation
} catch (Exception e) {
// Handle error
}
}
private Proxmox createClient() {
return Proxmox.create(
System.getenv("PROXMOX_HOST"),
Integer.parseInt(System.getenv("PROXMOX_PORT")),
System.getenv("PROXMOX_API_TOKEN")
);
}
}public class ProxmoxConfig {
public enum Environment {
DEVELOPMENT,
STAGING,
PRODUCTION
}
public static Proxmox createClient(Environment env) {
String prefix = env.name().toLowerCase();
String host = System.getenv(prefix + "_PROXMOX_HOST");
int port = Integer.parseInt(System.getenv(prefix + "_PROXMOX_PORT"));
String token = System.getenv(prefix + "_PROXMOX_TOKEN");
return Proxmox.create(host, port, token);
}
}Error: HTTP 401 - Unauthorized
Solutions:
- Verify token format:
USER@REALM!TOKENID=SECRET - Check token exists in Proxmox
- Ensure token is not expired
- Verify token has required permissions
Error: HTTP 403 - Forbidden
Solutions:
- Check token permissions in Proxmox
- Verify ACL settings for the resource
- Ensure privilege separation is configured correctly
public boolean testToken(Proxmox proxmox) {
try {
proxmox.getVersion().execute();
System.out.println("Token is valid");
return true;
} catch (ProxmoxAPIError e) {
if (e.getStatusCode() == 401) {
System.err.println("Token is invalid or expired");
} else if (e.getStatusCode() == 403) {
System.err.println("Token lacks necessary permissions");
}
return false;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}- Client Configuration - Configure Proxmox client
- Access Control - User and permission management
- Getting Started - Start using PVE4J
Getting Started
Core Concepts
Resource Management
Infrastructure
Security
Community