Authentication
NET Backup Vault uses short-lived JWT access tokens and rotating refresh tokens. Every protected endpoint requires an Authorization: Bearer <token> header. This page covers login, MFA, token lifecycle, and credential management.
Overview
All protected endpoints require a Bearer token in the request header. Tokens are issued on login and expire after a short window. Use the refresh endpoint to obtain a new access token without re-authenticating.
Authentication header
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Token lifecycle
| Token type | Lifetime | Use |
|---|---|---|
| Access token | Short (minutes) | Sent in Authorization header for every request |
| Refresh token | Long (days) | POST /api/auth/refresh to obtain a new access token |
| MFA temp token | Single use | Exchanged for access token after MFA verification |
Login
/api/auth/login
Authenticates with email and password. Returns JWT tokens on success. If MFA is enabled, returns a mfa_required: true response with a temporary token to be passed to POST /api/mfa/verify.
Request body
| Field | Type | Description |
|---|---|---|
| string | User email address | |
| password | string | User password |
Success response (200), no MFA
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"token_type": "bearer"
} MFA required response (200)
{
"mfa_required": true,
"temp_token": "eyJ0ZW1wIjp0cnVlLCJ1c2VyX2lkIjoiLi4uIn0..."
} cURL example
curl -X POST https://your-netbackupvault-host/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]", "password": "your-password"}' Multi-Factor Authentication
NET Backup Vault supports TOTP-based MFA (Google Authenticator, Authy, etc.) and single-use backup codes. MFA is optional per user and can be enabled at any time.
/api/mfa/setup Auth required
Initiates MFA enrollment. Returns a TOTP secret and a QR code URI to display in your app. The setup is not active until confirmed with POST /api/mfa/setup/confirm.
Success response (200)
{
"secret": "JBSWY3DPEHPK3PXP",
"qr_code_uri": "otpauth://totp/NetBackupVault:[email protected]?secret=JBSWY3DPEHPK3PXP&issuer=NetBackupVault"
} /api/mfa/setup/confirm Confirms MFA enrollment by verifying a TOTP code from the authenticator app. On success, MFA is active for all future logins.
| code | string | 6-digit TOTP code from the authenticator app |
/api/mfa/verify
Completes login when MFA is required. Pass the temp_token from the login response alongside the TOTP code. Returns the full LoginResponse with access and refresh tokens.
| temp_token | Temporary token returned by the login endpoint when mfa_required is true |
| code | 6-digit TOTP code from the authenticator app |
/api/mfa/verify-backup
Same as /api/mfa/verify but uses a single-use backup code instead of a TOTP code. Each backup code is consumed on use.
Other MFA endpoints
/api/mfa/disable Disable MFA. Requires current TOTP code to confirm.
/api/mfa/backup-codes/regenerate Invalidate existing backup codes and generate a fresh set. Requires current TOTP code.
/api/mfa/status Returns whether MFA is enabled for the current user.
Token Refresh
/api/auth/refresh Exchanges a valid refresh token for a new access token. The refresh token itself is rotated on each use; store the new one returned in the response.
| refresh_token | The refresh token issued at login or from the previous refresh call |
curl -X POST https://your-netbackupvault-host/api/auth/refresh \
-H "Content-Type: application/json" \
-d '{"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..."}' Current User
/api/auth/me Auth required Returns profile information for the currently authenticated user, including their role, customer association, and Meraki key IDs.
Success response (200)
{
"id": "uuid",
"email": "[email protected]",
"full_name": "Alex Admin",
"role": "system_admin",
"customer_id": "uuid",
"mfa_enabled": true,
"is_active": true,
"email_verified": true
} /api/auth/verify-token Lightweight token validation. Returns HTTP 200 if the Bearer token is valid and not expired. Useful as a health check for frontend session guards.
Logout
/api/auth/logout Auth required Invalidates the current session. Pass the refresh token in the request body to ensure server-side revocation.
| refresh_token | The refresh token to revoke. Recommended to prevent replay attacks. |
Password Management
/api/auth/change-password Auth required Changes the password for the currently authenticated user. Requires the current password for verification.
| current_password | The user's current password |
| new_password | The new password to set |
/api/auth/forgot-password Sends a password reset email if the address exists in the system. Always returns 200 regardless of whether the email exists (to prevent enumeration).
| Email address to send the reset link to |
/api/auth/reset-password Resets the password using the token from the reset email link.
| token | Reset token from the email link |
| new_password | The new password to set |
Email Verification
New accounts require email verification before full access is granted. The verification email contains a token that is passed to the verify endpoint.
/api/auth/verify-email Verify an email address using the token from the verification email. Body: { token: string }.
/api/auth/resend-verification Resend the verification email for the currently authenticated but unverified user.
/api/auth/verification-status Check whether the current user's email has been verified.
Error Reference
All errors follow a consistent JSON structure. Validation errors (422) include a detail array describing each invalid field.
| Status | Meaning |
|---|---|
| 401 Unauthorized | Missing or expired Bearer token. Re-authenticate or use the refresh endpoint. |
| 403 Forbidden | Valid token but insufficient permissions for the requested resource. |
| 422 Unprocessable | Request body or query parameters failed validation. Check the detail array. |
| 429 Too Many Requests | Rate limit exceeded on login or password reset endpoints. |
Validation error shape
{
"detail": [
{
"loc": ["body", "email"],
"msg": "value is not a valid email address",
"type": "value_error.email"
}
]
}