Email + Password
Configure email and password authentication in HelloJohn — registration flow, password policy, login, password reset, and email verification.
Email + password is the default authentication method. It's enabled out of the box with no configuration required.
Sign up
import { useAuth } from '@hellojohn/react'
function SignUpForm() {
const { signUp } = useAuth()
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
const form = new FormData(e.currentTarget)
await signUp({
email: form.get('email') as string,
password: form.get('password') as string,
name: form.get('name') as string,
})
}
return (
<form onSubmit={handleSubmit}>
<input name="name" type="text" placeholder="Full name" required />
<input name="email" type="email" placeholder="Email" required />
<input name="password" type="password" placeholder="Password" required />
<button type="submit">Create account</button>
</form>
)
}import { useAuth } from '@hellojohn/vue'
const { signUp } = useAuth()
async function handleSignUp(email: string, password: string, name: string) {
await signUp({ email, password, name })
}import { hellojohn } from './hellojohn'
await hellojohn.auth.signUp({
email: 'user@example.com',
password: 'SecurePassword123',
name: 'Alice Smith',
})curl -X POST https://your-instance.com/v1/auth/sign-up \
-H "Content-Type: application/json" \
-H "X-Client-Id: pk_live_XXXXXXXXXXXXXXXX" \
-d '{
"email": "user@example.com",
"password": "SecurePassword123",
"name": "Alice Smith"
}'Successful response:
{
"user": {
"id": "usr_01HABCDEF123456",
"email": "user@example.com",
"name": "Alice Smith",
"email_verified": false,
"created_at": "2026-01-15T10:00:00Z"
},
"session": {
"access_token": "eyJhbGci...",
"refresh_token": "rt_01HABCDEF...",
"expires_at": "2026-01-15T10:15:00Z"
}
}Sign in
import { useAuth } from '@hellojohn/react'
function SignInForm() {
const { signIn } = useAuth()
async function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault()
const form = new FormData(e.currentTarget)
await signIn({
email: form.get('email') as string,
password: form.get('password') as string,
})
}
return (
<form onSubmit={handleSubmit}>
<input name="email" type="email" placeholder="Email" required />
<input name="password" type="password" placeholder="Password" required />
<button type="submit">Sign in</button>
</form>
)
}curl -X POST https://your-instance.com/v1/auth/sign-in \
-H "Content-Type: application/json" \
-H "X-Client-Id: pk_live_XXXXXXXXXXXXXXXX" \
-d '{
"email": "user@example.com",
"password": "SecurePassword123"
}'Password policy
Configure minimum password requirements per tenant:
# Minimum password length (default: 8)
HELLOJOHN_PASSWORD_MIN_LENGTH=12
# Require at least one uppercase letter (default: false)
HELLOJOHN_PASSWORD_REQUIRE_UPPERCASE=true
# Require at least one number (default: false)
HELLOJOHN_PASSWORD_REQUIRE_NUMBER=true
# Require at least one special character (default: false)
HELLOJOHN_PASSWORD_REQUIRE_SPECIAL=true
# Check against HaveIBeenPwned database (default: false)
HELLOJOHN_PASSWORD_CHECK_HIBP=trueOr via the API:
curl -X PATCH https://your-instance.com/cp/v1/tenants/tnt_01HABCDEF \
-H "Authorization: Bearer {cp_admin_token}" \
-d '{
"password_policy": {
"min_length": 12,
"require_uppercase": true,
"require_number": true,
"check_hibp": true
}
}'Password validation error:
{
"error": "weak_password",
"message": "Password must be at least 12 characters and contain an uppercase letter.",
"violations": ["min_length", "require_uppercase"]
}Password reset
Request a reset link
curl -X POST https://your-instance.com/v1/auth/forgot-password \
-H "X-Client-Id: pk_live_XXXXXXXXXXXXXXXX" \
-d '{"email": "user@example.com"}'HelloJohn sends an email with a reset link. The link expires in 1 hour.
User clicks the link and sets a new password
The reset link contains a token: https://yourapp.com/reset-password?token=rt_...
curl -X POST https://your-instance.com/v1/auth/reset-password \
-H "X-Client-Id: pk_live_XXXXXXXXXXXXXXXX" \
-d '{
"token": "rt_01HABCDEF...",
"new_password": "NewSecurePassword456"
}'On success, all existing sessions are revoked and a new session is issued.
Password reset requires SMTP configuration. See SMTP Setup →.
Email verification
By default, users can sign in immediately after registration without verifying their email. To require verification:
# Require email verification before sign-in (default: false)
HELLOJOHN_EMAIL_VERIFICATION_REQUIRED=trueWhen enabled, sign-in attempts by unverified users return:
{
"error": "email_not_verified",
"message": "Please verify your email address before signing in."
}Resend verification email:
curl -X POST https://your-instance.com/v1/auth/resend-verification \
-H "X-Client-Id: pk_live_XXXXXXXXXXXXXXXX" \
-d '{"email": "user@example.com"}'Change password
Authenticated users can change their password:
curl -X POST https://your-instance.com/v1/users/me/change-password \
-H "Authorization: Bearer {access_token}" \
-d '{
"current_password": "OldPassword123",
"new_password": "NewPassword456"
}'Common errors
| Error | Cause | Solution |
|---|---|---|
invalid_credentials | Wrong email or password | Show generic error to user (don't leak which field is wrong) |
user_not_found | Email doesn't exist | Return same error as invalid credentials to prevent enumeration |
email_already_exists | Registering with an existing email | Show "Already have an account? Sign in" |
weak_password | Password doesn't meet policy | Show specific violations from the violations field |
email_not_verified | Email verification required and not done | Show resend verification link |
rate_limit_exceeded | Too many sign-in attempts | Show retry timer using retry_after from response |
Next steps
Authentication Overview
HelloJohn supports email/password, OAuth (9 providers), magic links, passkeys, and MFA. Learn which auth method to use and how they work together.
OAuth / Social Login
Add Google, GitHub, Apple, Microsoft, Discord, and 4 more OAuth providers to HelloJohn. Setup instructions, callback URLs, and SDK integration for all 9 providers.