Authentication

User Authentication

WoWSQL provides complete authentication for your application users. Enable auth in your project settings, then call these endpoints on your project host. Paths below are relative to the base URL. Send your anon key in the apikey header (the official SDKs do this for you).

Base URL: https://your-project-slug.wowsqlconnect.com/api/auth

The equivalent /auth/v1 prefix also works (for example /auth/v1/login); the gateway rewrites /api/auth/... to /auth/v1/....

User Registration

POST /signup

Headers:
  Content-Type: application/json

Body:
{
  "email": "user@example.com",
  "password": "securepassword123",
  "full_name": "John Doe",
  "user_metadata": {
    "company": "Acme Corp"
  }
}

User Login

POST /login

Headers:
  Content-Type: application/json

Body:
{
  "email": "user@example.com",
  "password": "securepassword123"
}

Response:
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refresh_token": "refresh_token_here",
  "user": {
    "id": "user-id",
    "email": "user@example.com",
    "email_verified": true
  }
}

If the user has two-factor authentication enabled, the response contains "requires_2fa": true and a pending_token instead of tokens; see Signing in when 2FA is enabled.

Get Current User

GET /me

Headers:
  Authorization: Bearer ACCESS_TOKEN

OAuth Authentication

Allow users to sign in with Google, GitHub, and other providers. Provider setup, the full flow, identity linking, errors and SDK examples are in OAuth for Projects.

Supported {provider} values (20 in the dashboard): google, github, microsoft, azure, apple, facebook, twitter, discord, gitlab, linkedin, twitch, spotify, notion, slack, bitbucket, figma, zoom, kakao, keycloak and workos. microsoft and azure are separate entries that both use Microsoft sign-in. Use twitter for X; x is not a provider value. keycloak can be saved but cannot be used for sign-in yet, so 19 providers work today. A provider must be configured (client ID and secret) and enabled for the project; otherwise the request returns 400.

GET /oauth/{provider}?frontend_redirect_uri=https://yourapp.com/auth/callback

Headers:
  apikey: YOUR_ANON_KEY

Response (JSON; the endpoint does not redirect):
{
  "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth?...",
  "provider": "google",
  "backend_callback_url": "https://your-project-slug.wowsqlconnect.com/auth/v1/oauth/google/callback",
  "frontend_redirect_uri": "https://yourapp.com/auth/callback"
}

// Optional: frontend_redirect_uri (defaults to the project's Frontend URL)
// Send the user's browser to authorization_url.
// Callback: the provider returns to /oauth/{provider}/callback, which
// redirects to frontend_redirect_uri with access_token, refresh_token,
// token_type, expires_in, user_id and email in the query string.

To let a third-party app such as Zapier or n8n work with one of your WoWSQL projects (WoWSQL as the OAuth server), see Sign in with WoWSQL (OAuth Connect).

Send passwordless login links via email:

POST /magic-link/send

Headers:
  Content-Type: application/json

Body:
{
  "email": "user@example.com"
}

// User clicks link in email
GET /magic-link/verify?token=VERIFICATION_TOKEN

Phone Number + OTP

SMS-based authentication:

POST /otp/send

Headers:
  Content-Type: application/json

Body:
{
  "phone": "+1234567890",
  "purpose": "login"
}

POST /otp/verify

Body:
{
  "phone": "+1234567890",
  "otp": "123456",
  "purpose": "login"
}

Phone numbers use E.164 format. For email OTP, send "email" instead of "phone". purpose is one of login, signup or password_reset (default login); for password_reset, also send new_password to /otp/verify.

Password Reset

POST /forgot-password

Headers:
  Content-Type: application/json

Body:
{
  "email": "user@example.com"
}

POST /reset-password

Body:
{
  "token": "reset_token_from_email",
  "new_password": "newsecurepassword123"
}

Email Verification

POST /verify-email

Headers:
  Authorization: Bearer ACCESS_TOKEN

// Or verify via email link
GET /verify-email?token=VERIFICATION_TOKEN

Two-Factor Authentication

Add an extra layer of security with 2FA. Your app users can protect their accounts with a time-based one-time password (TOTP) from an authenticator app (Google Authenticator, 1Password, Authy and similar). All 2FA endpoints are under the same base URL (/api/auth/2fa/... or /auth/v1/2fa/...).

POST /2fa/setup-totp

Headers:
  Authorization: Bearer ACCESS_TOKEN

// Returns the TOTP secret and a QR code for an authenticator app
Response:
{
  "secret": "JBSWY3DPEHPK3PXP",
  "otpauth_uri": "otpauth://totp/...",
  "qr_code_uri": "otpauth://totp/...",
  "qr_code_url": "data:image/png;base64,...",
  "qr_code_png": "data:image/png;base64,..."
}

POST /2fa/verify-and-enable

Headers:
  Authorization: Bearer ACCESS_TOKEN

Body:
{
  "totp_code": "123456"
}

Response:
{
  "success": true,
  "message": "Two-factor authentication enabled",
  "backup_codes": ["1a2b-3c4d", "..."],
  "recovery_codes": ["1a2b-3c4d", "..."]
}

POST /2fa/disable

Headers:
  Authorization: Bearer ACCESS_TOKEN

Body:
{
  "totp_code": "123456"
}
// or { "backup_code": "1a2b-3c4d" }

setup-totp returns 400 if 2FA is already enabled. qr_code_png is only present when the server can render a PNG; otherwise qr_code_url holds the otpauth:// URI. /2fa/verify-totp is an alias of /2fa/verify-and-enable, and code is accepted in place of totp_code on every 2FA endpoint. Enabling returns 8 single-use backup codes (format xxxx-xxxx); they are shown only in this response, so store them safely. Only TOTP is supported ("method": "totp", the default).

2FA status and backup codes

GET /2fa/status

Headers:
  Authorization: Bearer ACCESS_TOKEN

Response:
{
  "enabled": true,
  "method": "totp"
}

POST /2fa/recovery-codes      // alias: POST /2fa/backup-codes

Headers:
  Authorization: Bearer ACCESS_TOKEN

Body:
{
  "totp_code": "123456"
}

Response:
{
  "backup_codes": ["..."],
  "recovery_codes": ["..."]
}

Generating new codes replaces the old ones and requires a current authenticator code (not a backup code).

Signing in when 2FA is enabled

For a user with 2FA enabled, POST /login does not return tokens. It returns a short-lived challenge instead:

{
  "requires_2fa": true,
  "method": "totp",
  "email": "user@example.com",
  "pending_token": "eyJ...",
  "temp_token": "eyJ...",
  "message": "Two-factor authentication required"
}

Complete the sign-in with the authenticator code (or one backup code). No Authorization header is needed; the pending token identifies the user.

POST /2fa/verify-login

Body:
{
  "pending_token": "eyJ...",
  "totp_code": "123456"
}
// or "backup_code": "1a2b-3c4d" instead of "totp_code"

Response:
{
  "access_token": "eyJ...",
  "refresh_token": "eyJ...",
  "token_type": "bearer",
  "expires_in": 86400,
  "user": { "id": "user-id", "email": "user@example.com", "email_verified": true }
}

The pending token expires after 10 minutes (temp_token is accepted as an alias). A used backup code cannot be reused. Wrong codes return 400 "Invalid verification code"; an expired or invalid pending token returns 401. Verification endpoints allow 10 attempts per minute per client IP and return 429 after that.

expires_in follows the project's JWT expiry setting (default 24 hours = 86400 seconds). As with every endpoint on this page, also send your anon key in the apikey header.

Attack Protection: CAPTCHA (Cloudflare Turnstile)

You can require a CAPTCHA on your project's end-user auth endpoints to block bots and credential stuffing. CAPTCHA is off by default; while it is off, existing calls are unchanged.

1. Create your own Turnstile widget

WoWSQL does not provide a shared CAPTCHA widget. In the Cloudflare dashboard, create a Turnstile widget for the hostname(s) where your login page runs, then copy its site key (public) and secret key (private).

2. Enable it for the project

Go to Project → Authentication → Attack Protection, turn on CAPTCHA (provider: Turnstile), paste the Site key and Secret key, and save. Both keys are required to save with CAPTCHA on. The secret is stored encrypted and is never shown again; paste a new one to rotate it.

3. Read the site key and render the widget

GET https://your-project-slug.wowsqlconnect.com/auth/v1/settings
apikey: YOUR_ANON_KEY

Response (excerpt):
{
  "captcha": { "enabled": true, "provider": "turnstile", "site_key": "YOUR_SITE_KEY" }
}

4. Send the token with auth requests

When CAPTCHA is enabled, include the Turnstile token as captcha_token in the JSON body of these requests (or send it in a cf-turnstile-response or X-Captcha-Token header):

RequestEndpoint
Sign upPOST /signup
LoginPOST /login
Forgot passwordPOST /forgot-password
Send OTPPOST /otp/send
Send magic linkPOST /magic-link/send
Resend verification emailPOST /resend-verification
POST /login

Headers:
  Content-Type: application/json

Body:
{
  "email": "user@example.com",
  "password": "securepassword123",
  "captcha_token": "TURNSTILE_TOKEN"
}

SDKs (3.9.2 and later): pass captchaToken (TypeScript, Dart, C#, Java, Kotlin, Swift) or captcha_token (Python, PHP, Ruby); Go uses WithCaptchaToken(...) / a trailing token argument and Rust uses the *_with_captcha methods. See each Client SDK page.

Errors

StatusMessageMeaning
400Security check failed. Please try again.CAPTCHA is on and the token is missing or invalid.
503CAPTCHA is enabled but this project has no Turnstile secret. Add your Cloudflare site key and secret in Attack Protection.CAPTCHA is on but no secret key is saved.