Login
How to sign in to the EduShade platform — email, username, phone OTP, or social login
Login
EduShade supports multiple login methods so users can choose what's easiest for them.
Login Methods
1. Email/Username + Password Login
The standard login method.
Steps:
- Navigate to the Login page (
/auth/login) - Enter your email address or username
- Enter your password
- Click Login
- On success, you are redirected to your dashboard
Username rules: usernames are optional but, when present, must be 3+ characters and contain only lowercase letters, numbers, and ., -, _. Usernames are unique per tenant. They are typically set by an admin (admins can also edit usernames directly from /admin/users/{userID}/edit/edit-user — see User Management).
2. Phone + OTP Login
A passwordless login method using your phone number and a one-time password.
Steps:
- Navigate to the Login page
- Click the phone icon to switch to phone login mode
- Enter your phone number
- Click Send OTP — a 6-digit code is sent via SMS (
POST /v1/auth/otp/send) - Enter the OTP received on your phone
- Click Verify to log in (
POST /v1/auth/otp/verify)
OTP Details:
- 6-digit numeric code
- Expires after 10 minutes
- Up to 3 attempts per OTP
- 60-second cooldown before you can request a new one
3. Social Login
Log in instantly with Google or Facebook (the only providers currently visible in the UI). See OAuth & Social Login for the full provider matrix.
After Successful Login
When you log in successfully, the system:
- Creates a new session — tracking your device (type, OS, browser, brand/model) and location (IP, country, city, ISP, timezone)
- Issues tokens:
- Access Token (JWT) — short-lived, used for API requests
- Refresh Token — long-lived, used to refresh expired access tokens
- Records login details —
last_login_atandlast_login_ipare updated - Resets brute-force counters —
failed_login_attemptsis set back to 0 - Redirects you based on your user type:
| User Type | Redirect To |
|---|---|
| Admin / Instructor | /admin/dashboard |
| Learner | /dashboard |
If a ?intended=... URL was preserved (e.g. you were sent to login from a protected page), you are redirected there instead.
Verification Requirements
After login, the system checks if additional verification steps are needed:
| Check | Action |
|---|---|
| Email not verified | Redirect to /auth/verify-email |
| Phone not verified | Redirect to /auth/verify-phone |
| Profile incomplete | Redirect to /auth/complete-profile |
You must complete these steps before accessing the main platform.
Account Status Checks
Login is only allowed for accounts in certain statuses:
| Status | Can Login? | Behavior |
|---|---|---|
active | Yes | Normal login |
pending_verification | Yes | Logged in, then redirected to email/phone verification |
inactive | No | "Your account has been deactivated" |
suspended | No | "Your account has been suspended" |
deleted | No | "Account not found" (the email/phone is still soft-reserved during the retention window) |
Check Account Status (Pre-Login)
Before submitting credentials, the frontend can probe an account using:
- Endpoint:
GET /v1/auth/status - Accepts:
user_id,email,phone, orusername - Returns:
{ exists, status, email_verified, phone_verified, password_set }
This is used to choose the right login UX (e.g. show a password field vs an OTP-send button vs a "this user signed up via Google" hint), and to detect accounts that exist but have no password set (social-only accounts).
Token Management
Access Token
- Stored in
localStorageunderes_auth_access_token - Claims include:
user_id,tenant_id,email,username,phone,roles,permissions,exp,iat,nbf,jti(andimpersonated_by+view_modewhile impersonating) - Short-lived (configured per deployment, default 24h)
Refresh Token
- Stored in
localStorageunderes_auth_refresh_token - Tied to a specific session in the database
- Default lifetime: 7 days
Automatic Token Refresh
When an API request returns 401 Unauthorized, the frontend automatically:
- Calls
POST /v1/auth/refreshwith the refresh token - Stores the new access token (and refresh token if rotated)
- Retries the original request
If the refresh token is also expired/invalid, the user is logged out and redirected to login.
Security Features During Login
Brute Force Protection
The system protects against brute force attacks at two levels:
IP-Based Protection (Redis-backed, defined in auth-service/middlewares/brute_force.go):
- Tracks failed login attempts per IP address across all accounts
- After 20 failed attempts within 10 minutes, the IP is blocked for 30 minutes
Account-Based Lockout (escalating ladder, defined in auth-service/services/auth_service.go::lockoutDuration):
| Failed attempts on this account | Lock duration |
|---|---|
| 5+ | 1 minute |
| 10+ | 5 minutes |
| 15+ | 30 minutes |
| 20+ | 2 hours |
- The account's
locked_untiltimestamp is set on each lockout. - A successful login resets
failed_login_attemptsto 0.
Rate Limiting
The login endpoint is rate-limited to 10 requests per minute per IP address. See Security Features for the full rate-limit table.
Troubleshooting
| Issue | Solution |
|---|---|
| "Invalid credentials" | Double-check your email/username and password |
| "Account locked" / "Try again in X minutes" | Too many failed attempts. Wait for the lock to expire (1 → 5 → 30 min → 2 hr ladder) |
| "Account suspended" / "deactivated" | Contact your administrator |
| "Account not found" | No account exists with this email/phone/username. Register instead |
| OTP not received | Check your phone number, wait 60 seconds, then click "Resend OTP" |
| "Too many requests" | Rate limit hit. Wait 1 minute and try again |
| Stuck on loading | Clear browser cache, check internet connection |

