Skip to content

Authentication

Secure operator authentication with OAuth, OS keyring integration, and token management.

Nefia uses multiple authentication mechanisms across different layers: OAuth for operator identity, SSH public keys for target connections, and HMAC-signed tokens for VPN enrollment. Credentials are stored securely in the OS keyring whenever possible.

Operator Login

Authenticate with your Nefia account using the nefia login command:

bash
nefia login
nefia login

Opening browser for authentication...

Login successful! Account: operator@example.com Plan: Team (Unlimited devices) Token: stored in system keyring

Nefia uses a challenge-response flow inspired by PKCE (Proof Key for Code Exchange). Unlike approaches that spin up a local HTTP server, this works reliably in headless environments, remote shells, and containers.

1

The CLI generates a random 256-bit verifier and computes its SHA-256 hash (verifier hash). The verifier never leaves the CLI until the exchange step.

2

The CLI sends the verifier hash to POST /api/auth/cli/challenges. The server creates a challenge record and returns a challenge_id, poll_interval_ms (default 2 seconds), and expires_at (5-minute TTL).

3

The CLI opens your default browser to the dashboard approval page at /auth/cli?challenge=<id>. If the browser cannot be opened automatically, the URL is printed so you can open it manually.

4

You sign in via Clerk (email/password or SSO) and approve the pending challenge in the browser.

5

The CLI polls POST /api/auth/cli/challenges/{id}/exchange with the plaintext verifier. The server verifies the hash matches, then returns an access token and refresh token. Polling continues at the server-specified interval until approval or the 5-minute timeout.

6

The token pair is stored securely in the OS keyring.

Token Storage

Nefia stores authentication tokens using the platform's native secret storage:

Tokens are stored in macOS Keychain under the service name nefia-cli. You can inspect stored credentials using Keychain Access or the security CLI tool.

When vpn keygen successfully stores the private key in the OS keyring, no plaintext fallback is written. The config file stores only a keyring: reference.

When no keyring is available (headless servers, containers, CI environments), Nefia falls back to an AES-256-GCM encrypted file:

PlatformPath
macOS~/Library/Application Support/nefia/state/nefia-cli-api_token.json
Linux~/.config/nefia/state/nefia-cli-api_token.json
Windows%AppData%\nefia\state\nefia-cli-api_token.json

JWT Tokens

Nefia uses two JWT tokens signed with HS256:

TokenExpiryPurpose
Access token1 hourAuthenticates API requests
Refresh token30 daysSingle-use; exchanged for a new access/refresh token pair

The access token payload includes:

ClaimDescription
userIdInternal user ID
clerkIdClerk authentication provider ID
emailUser's email address
teamIdActive team ID (optional; included when a team context is set)

Refresh tokens use single-use rotation: each refresh token can only be used once. When the CLI refreshes the access token, the old refresh token is revoked and a new pair is issued. This limits the window of exposure if a token is compromised.

Team Context

When you switch teams with nefia team use <slug>, the active team ID is stored in nefia.yaml. Subsequent CLI API calls send that team context in the X-Nefia-Team-Id header, and the server verifies membership on every request. API requests are scoped to the active team -- hosts, schedules, and audit logs are isolated per team.

bash
# List your teams
nefia team list
 
# Switch to a shared team
nefia team use my-team
 
# Show current team context
nefia team

The server also supports X-Nefia-Team-Id for per-request overrides, and still falls back to the token claim or the personal team when no override is supplied.

Logout

Remove stored credentials with nefia logout:

bash
nefia logout
nefia logout

Token removed from system keyring. Logged out successfully.

This deletes the token from the OS keyring (or the encrypted fallback file). Active VPN tunnels are not affected — they use separate WireGuard keys.

SSH Key Authentication

Connections to target PCs use SSH public key authentication inside the VPN tunnel. Password authentication is disabled by default.

The SSH key pair is managed automatically during VPN enrollment. When a target is enrolled via nefia vpn invite and nefia-agent enroll, the operator's public key is registered on the target and the target's host key is recorded locally.

Host Key Verification (Trust On First Use)

Nefia uses a Trust On First Use (TOFU) model for SSH host key verification within the VPN:

  • Unknown host: The key is automatically accepted and persisted to the known_hosts file. This is safe because the VPN tunnel already authenticates the peer via WireGuard.
  • Known host, matching key: Connection proceeds normally.
  • Known host, changed key: Connection is rejected with a warning about potential man-in-the-middle attacks.

The TOFU callback uses a RWMutex to allow concurrent reads while serializing writes. The known_hosts file is created automatically with 0600 permissions if it does not exist. The file is stored at ~/.ssh/known_hosts on all platforms, following the standard SSH directory convention.

For testing environments where host keys change frequently:

bash
nefia exec --target test-box --insecure-skip-hostkey-check -- hostname

VPN Enrollment Tokens

Target PCs are enrolled using cryptographically signed invite tokens. Each token is signed with HMAC-SHA256, single-use (the nonce is consumed on first use), and time-limited (24 hours by default).

bash
nefia vpn invite --name staging-box --os macos --stun
# Valid --os values: macos, linux, windows
nefia vpn invite

Invite token generated:

Token: nf_inv_1a2b3c4d5e6f7g8h9i0j... Target: staging-box Expires: 2026-02-25T14:30:00Z (24h) Cloud relay: ready

Share this token securely with the target machine operator. Run on the target: nefia-agent enroll --token nf_inv_1a2b3c4d...

When the operator is logged in, a cloud relay session is automatically created so agents behind NAT/CGNAT can enroll without a direct TCP connection. The agent tries direct enrollment first (10 second timeout) and falls back to the cloud relay transparently.

If a token cannot be parsed (malformed base64, invalid JSON), the error message includes the original parsing error for easier debugging.

Agent Tokens

When a target PC is enrolled via nefia vpn invite, an agent-specific API token is generated for cloud communication (endpoint reporting, token rotation). This token is separate from the operator's OAuth tokens.

Token Generation (Bootstrap Code Flow)

Agent token issuance uses a two-phase bootstrap code flow:

1

The operator creates a cloud enrollment session via POST /api/enrollment/sessions. The request includes an expected_host_id that binds the session to a specific target.

2

The agent completes enrollment and the server issues a bootstrap code -- a short-lived JWT with a 5-minute TTL. The bootstrap code is returned in the enrollment result instead of a raw agent token.

3

The operator's CLI automatically exchanges the bootstrap code for a permanent agent token via POST /api/agent-tokens/bootstrap/exchange, passing the enrollment nonce and bootstrap code. Only the SHA-256 hash of the resulting token is stored server-side as an ApiToken record.

Token Storage

The agent stores its token using the same platform keyring as the operator CLI:

Stored in macOS Keychain under the service name nefia-agent-token.

When no keyring is available (headless servers, containers), the token is encrypted with AES-256-GCM and saved to a fallback file, following the same pattern as operator credentials.

Automatic Rotation

Agent tokens have a 90-day TTL. The agent checks the remaining TTL every 24 hours. When the TTL drops below 7 days, the agent automatically rotates the token:

  1. The agent calls POST /api/agent-tokens/rotate with its current token.
  2. The server verifies the current token, generates a new token, and revokes the old one atomically.
  3. The agent stores the new token in the keyring, replacing the previous value.

If rotation fails (network error, server unavailable), the agent retries with exponential backoff (5-minute base, 1-hour maximum). After a successful rotation, the normal 24-hour check cycle resumes. The existing token remains valid until its TTL expires.

Clipboard Copy

When generating invite tokens, use the --copy flag to copy the token to the clipboard automatically:

bash
nefia vpn invite --name staging-box --os linux --stun --copy

This avoids exposing the token in terminal scrollback. The clipboard is used as a secure alternative to printing the full token to stdout.

HTTPS Enforcement

All agent-to-cloud communication requires HTTPS. The validateCloudAPIBase() function rejects http:// URLs at configuration load time, ensuring agent tokens and endpoint data are never transmitted over unencrypted connections.

WireGuard Key Rotation

Nefia supports manual and automatic WireGuard key rotation for the operator.

Running nefia vpn keygen when a key already exists prompts for confirmation before overwriting, since this will disconnect all enrolled peers. Use --force to skip.

Manual Rotation

bash
nefia vpn rotate-key --grace-period 72h

This generates a new WireGuard keypair, distributes the new public key to all active peers via nefia vpn push-key, and retains the old key for the specified grace period. During the grace period, the agent accepts both the old and new keys, ensuring a smooth transition even if some agents are temporarily offline.

Automatic Rotation

Enable automatic key rotation in nefia.yaml (see Getting Started for platform-specific config file locations):

yaml
vpn:
  auto_rotate_interval: "720h"        # Rotate every 30 days
  key_rotation_grace_period: "72h"    # Accept old key for 3 days

When auto_rotate_interval is set, automatic key rotation is handled by the background scheduler started through nefia daemon run. If the agent reloads its configuration from disk during the grace period, it picks up the new key automatically.

Subscription Validation

Nefia validates your subscription to enforce device count limits:

PlanDevice LimitFeatures
Free2 devicesCore features
TeamUnlimitedPer-seat pricing, all features

Check your account status at any time:

bash
nefia account
nefia account

Email: operator@example.com Plan: Team Devices: 5 / Unlimited Status: Active (renews 2026-03-15)

Best Practices

Rotate credentials regularly

Run nefia logout followed by nefia login periodically to obtain fresh tokens. While tokens auto-refresh, periodic re-authentication reduces exposure if a token is compromised.

Use keyring storage whenever possible

The OS keyring provides hardware-backed encryption on most platforms. Avoid the encrypted file fallback in production — if you must use it, ensure the filesystem is encrypted at rest.

Secure invite token transmission

Never share invite tokens through unencrypted channels (plain email, HTTP, public chat). Use end-to-end encrypted messaging, direct SSH, or in-person exchange.

Security Overview

Understand Nefia's defense-in-depth security architecture.

VPN Setup Guide

Configure VPN tunnels, NAT traversal, and key rotation.