View .md

Auth endpoints (Client API: account)

31 FeatherPanel Client API: account endpoints from user/auth.php: methods, paths, auth, permissions, rate limits, parameters and responses.

Last synced from FeatherPanel 15b94e9 on .

On this page

Defined in backend/app/routes/user/auth.php. Authentication used here: Public, Signed-in user. Read Authentication for how to send credentials and Rate limits and errors for the response envelope.

Paths, methods, permissions and rate limits come from the route file. Summaries, parameters and response codes come from the OpenAPI annotations on the controllers; endpoints without annotations show only what the route file declares.

Endpoints

PUT/api/user/auth/register

Auth: PublicDefault rate limit: 5 / minute (user-auth)Route name: registerController: RegisterController::putroute source

Register new user Create a new user account with email verification and welcome email. User is automatically logged in after successful registration. Includes CloudFlare Turnstile validation if enabled.

Request body: RegisterRequest (application/json) · Response data: RegisterResponse

Body fieldTypeRequiredDescription
usernamestringyesUsername (alphanumeric and underscores only)
emailstring (email)yesUser email address
passwordstringyesUser password
first_namestringyesUser first name
last_namestringyesUser last name
turnstile_tokenstringnoCloudFlare Turnstile token (required if Turnstile is enabled)
Response data fieldTypeDescription
userobjectUser information
preferencesobjectUser preferences
messagestringSuccess message
curl -X PUT "$PANEL_URL/api/user/auth/register" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"username":"","email":"","password":"","first_name":"","last_name":"","turnstile_token":""}'

Plugin events: featherpanel:auth:login:success, featherpanel:auth:register:success, featherpanel:auth:registration:failed

Responses: 200 User registered successfully and automatically logged in · 400 Bad request - Missing required fields, invalid data format, Turnstile validation failed, or Turnstile keys not set · 403 Forbidden - Registration is not enabled · 409 Conflict - Username or email already exists · 500 Internal server error - Failed to create user

PUT/api/user/auth/login

Auth: PublicDefault rate limit: 10 / minute (user-auth)Route name: loginController: LoginController::putroute source

Login user Authenticate user with username or email and password. Includes CloudFlare Turnstile validation if enabled. Returns 2FA requirement if enabled.

Request body: LoginRequest (application/json)

Body fieldTypeRequiredDescription
username_or_emailstringyesUser email address or username
passwordstringyesUser password
turnstile_tokenstringnoCloudFlare Turnstile token (required if Turnstile is enabled)
curl -X PUT "$PANEL_URL/api/user/auth/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"username_or_email":"","password":"","turnstile_token":""}'

Plugin events: featherpanel:auth:login:failed

Responses: 200 User logged in successfully or two-factor authentication required · 400 Bad request - Missing required fields, invalid username or email format, Turnstile validation failed, or Turnstile keys not set · 401 Unauthorized - Invalid credentials, user is banned, or authentication otherwise rejected · 500 Internal server error - Remember token not set

PUT/api/user/auth/forgot-password

Auth: PublicDefault rate limit: 5 / minute (user-auth)Route name: forgot-passwordController: ForgotPasswordController::putroute source

Request password reset Send a password reset email to the user. Includes CloudFlare Turnstile validation if enabled.

Request body: ForgotPasswordRequest (application/json) · Response data: ForgotPasswordResponse

Body fieldTypeRequiredDescription
emailstring (email)yesUser email address
turnstile_tokenstringnoCloudFlare Turnstile token (required if Turnstile is enabled)
Response data fieldTypeDescription
messagestringSuccess message
curl -X PUT "$PANEL_URL/api/user/auth/forgot-password" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"email":"","turnstile_token":""}'

Plugin events: featherpanel:auth:forgot:password, featherpanel:auth:forgot:password:failed

Responses: 200 Generic success whether or not the email belongs to an account, including when User::updateUser() fails (anti-enumeration). Reset email is queued asynchronously when an account exists. · 400 Bad request - Missing required fields, invalid email format, Turnstile validation failed, or Turnstile keys not set

GET/api/user/auth/reset-password

Auth: PublicDefault rate limit: 10 / minute (user-auth)Route name: reset-password-getController: ResetPasswordController::getroute source

Validate reset token Validate a password reset token to check if it is valid before allowing password reset.

ParameterInTypeRequiredDescription
tokenquerystringyesPassword reset token from email

Response data: TokenValidationResponse

Response data fieldTypeDescription
messagestringToken validation message
tokenstringValidated token
curl -X GET "$PANEL_URL/api/user/auth/reset-password?token=$TOKEN" \
  -H "Accept: application/json"

Responses: 200 Token is valid · 400 Bad request - Missing token or invalid token · 500 Internal server error - Failed to validate token

GET/api/user/auth/verify-email

Auth: PublicDefault rate limit: 10 / minute (user-auth)Route name: verify-email-getController: VerifyEmailController::getroute source
curl -X GET "$PANEL_URL/api/user/auth/verify-email" \
  -H "Accept: application/json"

POST/api/user/auth/verify-email/resend

Auth: PublicDefault rate limit: 3 / minute (user-auth-verify-email)Route name: verify-email-resendController: VerifyEmailController::resendroute source
curl -X POST "$PANEL_URL/api/user/auth/verify-email/resend" \
  -H "Accept: application/json"

PUT/api/user/auth/reset-password

Auth: PublicDefault rate limit: 5 / minute (user-auth)Route name: reset-password-putController: ResetPasswordController::putroute source

Reset password Reset user password using token from forgot password email. Includes CloudFlare Turnstile validation if enabled.

Request body: ResetPasswordRequest (application/json) · Response data: ResetPasswordResponse

Body fieldTypeRequiredDescription
tokenstringyesPassword reset token from email
passwordstringyesNew password
turnstile_tokenstringnoCloudFlare Turnstile token (required if Turnstile is enabled)
Response data fieldTypeDescription
messagestringSuccess message
curl -X PUT "$PANEL_URL/api/user/auth/reset-password" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"token":"","password":"","turnstile_token":""}'

Plugin events: featherpanel:auth:password:reset:failed, featherpanel:auth:reset:password:success

Responses: 200 Password reset successfully · 400 Bad request - Missing required fields, Turnstile validation failed, or Turnstile keys not set · 404 Not found - Invalid token · 500 Internal server error - Failed to reset password

PUT/api/user/auth/two-factor

Auth: Signed-in userDefault rate limit: 10 / minute (user-auth)Route name: two-factorController: TwoFactorController::putroute source

Enable two-factor authentication Enable two-factor authentication for the authenticated user using TOTP code verification. Includes CloudFlare Turnstile validation if enabled.

Request body: TwoFactorEnableRequest (application/json) · Response data: TwoFactorEnableResponse

Body fieldTypeRequiredDescription
codestringyes6-digit TOTP code
secretstringyes16-character secret key
turnstile_tokenstringnoCloudFlare Turnstile token (required if Turnstile is enabled)
Response data fieldTypeDescription
userobjectUser information
messagestringSuccess message
curl -X PUT "$PANEL_URL/api/user/auth/two-factor" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"code":"","secret":"","turnstile_token":""}'

Plugin events: featherpanel:auth:2fa:enabled

Responses: 200 Two-factor authentication enabled successfully · 400 Bad request - Missing required fields, invalid code length, Turnstile validation failed, or Turnstile keys not set · 401 Unauthorized - Invalid TOTP code or user is banned · 500 Internal server error - Failed to enable 2FA

GET/api/user/auth/two-factor

Auth: Signed-in userRoute name: two-factor-getController: TwoFactorController::getroute source

Get two-factor setup Get QR code URL and secret key for setting up two-factor authentication with an authenticator app.

Response data: TwoFactorSetupResponse

Response data fieldTypeDescription
qr_code_urlstringQR code URL for authenticator app
secretstringSecret key for manual entry
messagestringSuccess message
curl -X GET "$PANEL_URL/api/user/auth/two-factor" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"

Plugin events: featherpanel:auth:2fa:setup

Responses: 200 Two-factor setup information retrieved successfully · 400 Bad request - Two-factor authentication already enabled · 401 Unauthorized - User not authenticated · 500 Internal server error - Failed to generate setup information

GET/api/user/auth/logout

Auth: PublicDefault rate limit: 30 / minute (user-auth)Route name: auth-logoutController: AuthLogoutController::getroute source

Logout user Logout the authenticated user by clearing remember token cookie and updating user session. Blocks 2FA if enabled.

Response data: LogoutResponse

Response data fieldTypeDescription
messagestringLogout success message
curl -X GET "$PANEL_URL/api/user/auth/logout" \
  -H "Accept: application/json"

Plugin events: featherpanel:auth:logout

Responses: 200 User logged out successfully · 500 Internal server error - Failed to logout user

DELETE/api/user/auth/logout

Auth: PublicDefault rate limit: 30 / minute (user-auth)Route name: auth-logoutController: AuthLogoutController::getroute source

Logout user Logout the authenticated user by clearing remember token cookie and updating user session. Blocks 2FA if enabled.

Response data: LogoutResponse

Response data fieldTypeDescription
messagestringLogout success message
curl -X DELETE "$PANEL_URL/api/user/auth/logout" \
  -H "Accept: application/json"

Plugin events: featherpanel:auth:logout

Responses: 200 User logged out successfully · 500 Internal server error - Failed to logout user

POST/api/user/auth/two-factor

Auth: PublicDefault rate limit: 10 / minute (user-auth)Route name: auth-two-factor-postController: TwoFactorController::postroute source

Verify two-factor code Verify two-factor authentication code during login process to complete authentication.

Request body: TwoFactorVerifyRequest (application/json) · Response data: TwoFactorVerifyResponse

Body fieldTypeRequiredDescription
emailstring (email)yesUser email address
codestringyes6-digit TOTP code
challengestringyesChallenge token from the password authentication step (TWO_FACTOR_REQUIRED)
Response data fieldTypeDescription
userobjectUser information
messagestringSuccess message
curl -X POST "$PANEL_URL/api/user/auth/two-factor" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"email":"","code":"","challenge":""}'

Plugin events: featherpanel:auth:2fa:failed, featherpanel:auth:2fa:verified, featherpanel:auth:login:success

Responses: 200 Two-factor authentication verified successfully · 400 Bad request - Missing email, code, or challenge · 401 Unauthorized - 2FA not enabled, invalid code, or missing/invalid challenge · 429 Too many failed 2FA attempts for this account · 500 Internal server error - Failed to verify 2FA

GET/api/user/auth/discord/login

Auth: PublicRoute name: discord-loginController: DiscordController::loginroute source
curl -X GET "$PANEL_URL/api/user/auth/discord/login" \
  -H "Accept: application/json"

GET/api/user/auth/discord/callback

Auth: PublicDefault rate limit: 10 / minute (user-auth-discord)Route name: discord-callbackController: DiscordController::callbackroute source
curl -X GET "$PANEL_URL/api/user/auth/discord/callback" \
  -H "Accept: application/json"

PUT/api/user/auth/discord/register

Auth: PublicDefault rate limit: 5 / minute (user-auth-discord)Route name: discord-registerController: DiscordController::registerroute source
curl -X PUT "$PANEL_URL/api/user/auth/discord/register" \
  -H "Accept: application/json"

GET/api/user/auth/oidc/login

Auth: PublicDefault rate limit: 10 / minute (user-auth-oidc)Route name: oidc-loginController: OidcController::loginroute source

Initiate OIDC login Redirects the user to the configured OpenID Connect (OIDC) provider.

curl -X GET "$PANEL_URL/api/user/auth/oidc/login" \
  -H "Accept: application/json"

GET/api/user/auth/oidc/callback

Auth: PublicDefault rate limit: 10 / minute (user-auth-oidc)Route name: oidc-callbackController: OidcController::callbackroute source

OIDC callback Handles the OpenID Connect (OIDC) callback and logs the user in.

curl -X GET "$PANEL_URL/api/user/auth/oidc/callback" \
  -H "Accept: application/json"

POST/api/user/auth/email-login/request

Auth: PublicDefault rate limit: 3 / minute (user-auth-email)Route name: email-login-requestController: EmailLoginController::requestCoderoute source

Request email login code Send a 6-digit login code to the user's email address for passwordless authentication.

Request body: EmailLoginRequest (application/json) · Response data: EmailLoginCodeSentResponse

Body fieldTypeRequiredDescription
emailstring (email)yesUser email address
turnstile_tokenstringnoCloudFlare Turnstile token (required if Turnstile is enabled)
Response data fieldTypeDescription
messagestringSuccess message
emailstringEmail address where code was sent
curl -X POST "$PANEL_URL/api/user/auth/email-login/request" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"email":"","turnstile_token":""}'

Plugin events: featherpanel:auth:email:login:code:requested, featherpanel:auth:login:failed

Responses: 200 Login code sent successfully · 400 Bad request - Missing email, invalid format, or Turnstile validation failed · 401 Unauthorized - Email not found or user is banned · 403 Forbidden - Email login is disabled · 429 Too many requests - Rate limited

POST/api/user/auth/email-login/verify

Auth: PublicDefault rate limit: 10 / minute (user-auth-email)Route name: email-login-verifyController: EmailLoginController::verifyCoderoute source

Verify email login code Verify the 6-digit login code and authenticate the user.

Request body: EmailLoginVerifyRequest (application/json) · Response data: LoginResponse

Body fieldTypeRequiredDescription
emailstring (email)yesUser email address
codestringyes6-digit login code sent to email
Response data fieldTypeDescription
userobjectUser information
preferencesobjectUser preferences
messagestringSuccess message
curl -X POST "$PANEL_URL/api/user/auth/email-login/verify" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"email":"","code":""}'

Plugin events: featherpanel:auth:login:failed

Responses: 200 User logged in successfully · 400 Bad request - Missing fields or invalid code format · 401 Unauthorized - Invalid or expired code · 403 Forbidden - Email login is disabled

POST/api/user/auth/qr/start

Auth: PublicDefault rate limit: 30 / minute (user-auth-qr-start)Route name: qr-login-startController: QrLoginController::startroute source

Start QR login challenge Creates a short-lived QR login challenge for Discord-style sign-in from a phone that is already logged in.

curl -X POST "$PANEL_URL/api/user/auth/qr/start" \
  -H "Accept: application/json"

Responses: 200 Challenge created · 429 Rate limited

POST/api/user/auth/qr/poll

Auth: PublicDefault rate limit: 60 / minute (user-auth-qr-poll)Route name: qr-login-pollController: QrLoginController::pollroute source

Poll QR login challenge Desktop polls challenge status. When approved, returns a one-time exchange_token.

curl -X POST "$PANEL_URL/api/user/auth/qr/poll" \
  -H "Accept: application/json"

Responses: 200 Challenge status · 400 Invalid challenge or secret · 429 Polling too fast

POST/api/user/auth/qr/exchange

Auth: PublicDefault rate limit: 30 / minute (user-auth-qr-exchange)Route name: qr-login-exchangeController: QrLoginController::exchangeroute source

Exchange QR login token for session Desktop redeems the one-time exchange_token and receives the remember_token cookie via completeLogin.

curl -X POST "$PANEL_URL/api/user/auth/qr/exchange" \
  -H "Accept: application/json"

Responses: 200 Logged in · 400 Invalid or expired token · 403 User banned or deleted

GET/api/user/auth/qr/code/{user_code}

Auth: Signed-in userDefault rate limit: 30 / minute (user-auth-qr-approval)Route name: qr-login-show-by-codeController: QrLoginController::showByCoderoute source

Look up QR login challenge by user code Authenticated user enters the short code shown on another device to load and mark the challenge as scanned.

ParameterInTypeRequiredDescription
user_codepath-yes
curl -X GET "$PANEL_URL/api/user/auth/qr/code/$USER_CODE" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"

Responses: 200 Challenge details · 400 Invalid or expired code · 401 Unauthorized

GET/api/user/auth/qr/{challenge_id}

Auth: Signed-in userDefault rate limit: 30 / minute (user-auth-qr-approval)Route name: qr-login-showController: QrLoginController::showroute source

Get QR login challenge for approval Authenticated phone loads challenge details and marks it as scanned.

ParameterInTypeRequiredDescription
challenge_idpath-yes
curl -X GET "$PANEL_URL/api/user/auth/qr/$CHALLENGE_ID" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"

Responses: 200 Challenge details · 400 Invalid or expired challenge · 401 Unauthorized

POST/api/user/auth/qr/{challenge_id}/approve

Auth: Signed-in userDefault rate limit: 30 / minute (user-auth-qr-approval)Route name: qr-login-approveController: QrLoginController::approveroute source

Approve QR login challenge Authenticated phone approves the desktop login. Does not set a cookie on the phone; mints an exchange token for the desktop.

ParameterInTypeRequiredDescription
challenge_idpath-yes
curl -X POST "$PANEL_URL/api/user/auth/qr/$CHALLENGE_ID/approve" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"

Responses: 200 Approved · 400 Invalid challenge · 401 Unauthorized · 403 User banned or deleted

POST/api/user/auth/qr/{challenge_id}/deny

Auth: Signed-in userDefault rate limit: 30 / minute (user-auth-qr-approval)Route name: qr-login-denyController: QrLoginController::denyroute source

Deny QR login challenge

ParameterInTypeRequiredDescription
challenge_idpath-yes
curl -X POST "$PANEL_URL/api/user/auth/qr/$CHALLENGE_ID/deny" \
  -H "Authorization: Bearer $FEATHERPANEL_API_KEY" \
  -H "Accept: application/json"

Responses: 200 Denied · 400 Invalid challenge · 401 Unauthorized