EduShade
Auth Module

Security Features

Brute force protection, rate limiting, account lockout, JWT, headers, audit publishing, and tenant isolation

Security Features

EduShade implements multiple layers of security to protect user accounts and prevent unauthorized access.

Brute Force Protection

IP-Based Protection

Defined in auth-service/middlewares/brute_force.go, backed by Redis (with an in-memory fallback if Redis is unavailable).

ParameterValue
Threshold20 failed attempts
Time window10 minutes
Block duration30 minutes

How it works:

  1. Every failed login from an IP is recorded against that IP (across all accounts targeted from that IP).
  2. When the IP accumulates 20 failures within 10 minutes, it is blocked.
  3. All login requests from that IP are rejected for 30 minutes.
  4. After the block expires, the counter resets.

Account-Based Lockout

Defined in auth-service/services/auth_service.go::lockoutDuration. Each user account tracks failed_login_attempts and a locked_until timestamp.

Failed attempts on this accountLock duration
5+1 minute
10+5 minutes
15+30 minutes
20+2 hours

A successful login resets failed_login_attempts to 0.

What Users See

  • Before lockout: normal login error messages
  • During IP block: "Too many failed attempts. Please try again later."
  • During account lock: "Your account has been temporarily locked. Try again in X minutes."

Rate Limiting

Every public endpoint has rate limits, tracked per IP via Redis.

EndpointLimit
Login10 / minute
Register5 / 5 minutes
Forgot Password3 / 5 minutes
Reset Password5 / 5 minutes
Verify Email10 / minute
Verify Phone10 / minute
Resend Email Verification3 / 5 minutes
Resend Phone Verification3 / 5 minutes
Send OTP3 / 5 minutes
Verify OTP10 / minute
Refresh Token30 / minute

When a rate limit is exceeded the API returns 429 Too Many Requests.

JWT Security

Token Structure

PropertyValue
AlgorithmHS256 (HMAC-SHA256)
SecretServer-side configured, never exposed
Issueredushade-auth (default)
Audienceedushade-users (default)
Default access token lifetime24 hours
Default refresh token lifetime7 days (168 h)

Token Claims

Each access token contains:

ClaimDescription
user_idAuthenticated user's ID
tenant_idUser's tenant (multi-tenancy)
emailUser's email
usernameUser's username (if set)
phoneUser's phone (if set)
rolesArray of role names
permissionsArray of permission names
impersonated_byAdmin's user ID — present only during impersonation/masquerade
view_mode"impersonation" (read-only) or "masquerade" (full access) — present only during impersonation
exp, iat, nbfStandard timing claims
jtiUnique JWT identifier (used for revocation)

See User Impersonation for how impersonated_by and view_mode are used.

Token Revocation

  • Each session row stores the access token's JTI so it can be invalidated on logout.
  • Refresh tokens are stored in the user_sessions table and are revoked when:
    • The user explicitly logs out
    • An admin terminates the session
    • The refresh token expires
  • A revoked refresh token cannot be used to obtain a new access token.

Audit & Activity Event Publishing

The auth-service emits two separate streams of events. Downstream services (notifications, audit, analytics) consume them independently.

Notification Events (pub/sub EventType)

Published via the notification event bus — consumed by the notification service for emails, push, in-app messages, etc.

EventTypeTriggered by
user.registeredSuccessful registration
user.email_verifiedEmail verification completed
user.phone_verifiedPhone verification completed
user.login_new_deviceLogin from a new OS/Browser combination
user.password_changedSelf-service password change
user.password_reset_requestedForgot-password flow initiated
user.otp_verificationOTP issued for verification

Activity Events (Action field → activity logs)

Written to the activity log table and surfaced to admins via Audit Logs (requires audit.view) and to users via Account Settings → Activity Logs.

ActionTriggered by
register, login, logoutBasic auth lifecycle
forgot_password, password_reset, password_changedPassword flows
email_changed, phone_changed, account_updated, account_deletedSelf-service account changes
email_verified, phone_verifiedVerification completions
oauth_login, oauth_linked, oauth_unlinkedOAuth sign-in and connection changes
impersonation_started, impersonation_stoppedImpersonation transitions (include view_mode)
created, updated, deleted, bulk_deletedAdmin user management
role_assigned, role_removed, permission_added, permission_removedRBAC assignment changes

Every entry carries the actor (user or admin), tenant ID, target ID, IP, user agent, and timestamp.

Security Headers

The API server sets security headers on responses:

HeaderValuePurpose
X-Frame-OptionsDENY / SAMEORIGINPrevent clickjacking
Content-Security-PolicyConfigured per deploymentControl resource loading
X-Content-Type-OptionsnosniffPrevent MIME sniffing
X-XSS-Protection1; mode=blockBrowser XSS filter
Strict-Transport-Securitymax-age=31536000; includeSubDomainsForce HTTPS

CORS

  • CORS is configured per deployment.
  • Only allow-listed origins can make API requests.

Request ID Tracking

Every API request is assigned a unique Request ID (via the OTEL middleware). The ID is logged on the backend and included in error responses for support reference, allowing frontend errors to be correlated with backend traces.

Multi-Tenant Isolation

Security is enforced at the tenant level:

  • Every database query is scoped to the current tenant's tenant_id.
  • Unique constraints are tenant-scoped (e.g. the email index includes tenant_id).
  • Roles, permissions, sessions, and OAuth state are all tenant-isolated.
  • OAuth state validation includes a tenant check to prevent cross-tenant attacks.

Password Security

  • Passwords are hashed with bcrypt before storage. Raw passwords are never logged.
  • Password complexity rules are enforced at registration and change time.
  • Password reset tokens are time-limited (1 hour).
  • OTP codes expire after 10 minutes with a maximum of 3 attempts per OTP.
  • Tenant-configurable password policy (see Password Management).

Soft Deletes & Data Retention

  • Users, roles, and sessions support soft delete (a deleted_at timestamp).
  • Unique indexes on email, phone, and username are conditional (WHERE deleted_at IS NULL), so a deleted user's email can be reused later.
  • Data retention policies are configurable per tenant — supports GDPR-style requirements.

OAuth State Security

OAuth flows use an encrypted state parameter:

  • Encodes tenant ID, provider, a cryptographic token, and an expiry.
  • Validated on callback for tampering, replay, and cross-tenant attacks.

Verification Token & OTP Security

  • Email verification can use either an OTP or a base64-encoded token in the verification link (which auto-fills the OTP form).
  • OTPs are 6-digit random codes.
  • Email and phone verification OTP expiry: 10 minutes. Password reset token expiry: 1 hour.
  • Maximum 3 attempts per OTP record; failed attempts increment a counter and lock the OTP.

Best Practices for Users

  1. Use a strong password that meets the platform's policy.
  2. Verify your email and phone to secure your account.
  3. Review your active sessions regularly in Account Settings → Devices.
  4. Terminate any unfamiliar sessions immediately.
  5. Don't share your credentials — admins can use Impersonation for support.
  6. Log out on shared or public devices.

Troubleshooting

IssueSolution
Account lockedWait for the lock duration (1 / 5 / 30 min / 2 hr ladder) or contact an admin
IP blockedWait 30 minutes for the block to expire
Rate limit exceededWait for the specified duration and try again
"Invalid token" errorsYour session may have expired — log in again
Suspicious sessionsTerminate all sessions and change your password

On this page