Login Blueprint
Authenticate a user with email and password
| Feature | login |
| Category | Auth |
| Version | 1.0.0 |
| Tags | authentication, session, security, identity, saas |
| YAML Source | View on GitHub |
| JSON API | login.json |
Fields
| Name | Type | Required | Label | Description |
|---|---|---|---|---|
email | Yes | Email Address | Validations: required, email, maxLength | |
password | password | Yes | Password | Validations: required, minLength, maxLength |
remember_me | boolean | No | Remember me |
Rules
- security:
- max_attempts: 5
- lockout_duration_minutes: 15
- lockout_scope: per_email
- rate_limit:
- window_seconds: 60
- max_requests: 10
- scope: per_ip
- password_comparison:
- constant_time: true
- credential_error_handling:
- generic_message: true
- session:
- type: jwt
- access_token:
- expiry_minutes: 15
- refresh_token:
- expiry_days: 7
- rotate_on_use: true
- remember_me_expiry_days: 30
- extend_on_activity: true
- secure_flags:
- http_only: true
- secure: true
- same_site: strict
- email:
- require_verified: true
- case_sensitive: false
- trim_whitespace: true
Outcomes
Rate_limited (Priority: 1) — Error: LOGIN_RATE_LIMITED
Given:
request_count(computed) gt10
Result: show “Too many login attempts. Please wait a moment.”
Account_locked (Priority: 2) — Error: LOGIN_ACCOUNT_LOCKED
Given:
failed_login_attempts(db) gte5locked_until(db) gtnow
Then:
- emit_event event:
login.locked
Result: show “Account temporarily locked. Please try again later.”
Account_disabled (Priority: 3) — Error: LOGIN_ACCOUNT_DISABLED
Given:
status(db) eqdisabled
Result: show “This account has been disabled. Please contact support.”
Invalid_credentials (Priority: 4) — Error: LOGIN_INVALID_CREDENTIALS | Transaction: atomic
Given:
- ANY:
user(db) not_exists ORpassword(input) neqstored_hash
Then:
- set_field target:
failed_login_attemptsvalue:increment— Increment failed attempt counter - emit_event event:
login.failed - set_field target:
locked_untilvalue:now + 15mwhen:failed_login_attempts >= 5— Lock account if attempts reach 5 - emit_event event:
login.lockedwhen:failed_login_attempts >= 5
Result: show “Invalid email or password” (SAME message for both cases — enumeration prevention)
Email_not_verified (Priority: 5) — Error: LOGIN_EMAIL_NOT_VERIFIED
Given:
email_verified(db) eqfalse
Then:
- emit_event event:
login.unverified
Result: redirect to /verify-email with message “Please verify your email before logging in”
Successful_login (Priority: 10) | Transaction: atomic
Given:
email(input) matches^[^\s@]+@[^\s@]+\.[^\s@]+$user(db) existspassword(input) eqstored_hashstatus(db) neqdisabledemail_verified(db) eqtrue
Then:
- set_field target:
failed_login_attemptsvalue:0— Reset attempt counter on success - create_record target:
session— Create JWT access token (15-min) + refresh token (7-day, or 30-day if remember_me) - emit_event event:
login.success
Result: redirect to /dashboard
Errors
| Code | Status | Message | Retry |
|---|---|---|---|
LOGIN_INVALID_CREDENTIALS | 401 | Invalid email or password | Yes |
LOGIN_ACCOUNT_LOCKED | 423 | Account temporarily locked. Please try again later. | No |
LOGIN_EMAIL_NOT_VERIFIED | 403 | Please verify your email address to continue | No |
LOGIN_ACCOUNT_DISABLED | 403 | This account has been disabled. Please contact support. | No |
LOGIN_RATE_LIMITED | 429 | Too many login attempts. Please wait a moment. | Yes |
LOGIN_VALIDATION_ERROR | 422 | Please check your input and try again | Yes |
Events
| Event | Description | Payload |
|---|---|---|
login.success | User successfully authenticated | user_id, email, timestamp, ip_address, user_agent, session_id |
login.failed | Authentication attempt failed | email, timestamp, ip_address, user_agent, attempt_count, reason |
login.locked | Account locked due to too many failures | email, user_id, timestamp, lockout_until, attempt_count |
login.unverified | Login blocked — email not verified | user_id, email, timestamp |
Related Blueprints
| Feature | Relationship | Reason |
|---|---|---|
| signup | required | User must exist before they can log in |
| password-reset | recommended | Users will forget passwords |
| email-verification | recommended | Required when rules.email.require_verified is true |
| logout | required | Every login needs a logout |
| biometric-auth | optional | Palm vein scan as an alternative to password login |