Login, 2FA and sessions
ZEUS protects console access with several layers. Understanding them helps you avoid the most common problems (e.g. a "login loop" caused by the wrong email address).
Step 1 — password
You log in with an email + password pair. The backend verifies:
- the email via
hmac.compare_digest(constant-time comparison), - the password via bcrypt (also constant-time),
- and in on-prem/hybrid mode it additionally attempts an LDAP bind to Active Directory.
Tip: the email must match the specific deployment.
admin@lsn.iois the admin of the lsn instance, andadmin@z3us.iois the admin of the MVP. A mistake = wrong credentials and a bounce back to the login screen.
Login is protected by a rate limit: 10 failed attempts/IP in 5 minutes and
5 attempts/email in 15 minutes → 429 Too Many Requests. A successful login resets the counters.
Step 2 — 2FA via email
If 2FA is enabled, the backend does not issue a token right away. Instead it
sends a 6-digit code by email (provider Resend) and returns a challenge_token.
You redeem the code via POST /auth/verify-2fa:
POST /auth/login → { requires_2fa: true, challenge_token, email_hint }
POST /auth/verify-2fa{ challenge_token, code } → { access_token (JWT) }
POST /auth/resend-2fa→ resend the code (attempt limit)
Codes are single-use, have a short TTL and an attempt limit per challenge.
Domain allowlist
The ZEUS_ALLOWED_EMAIL_DOMAINS variable (e.g. professnet.pl) restricts whose accounts
can authenticate — checked at login and on every request. An empty
value = disabled (dev/test). Enforced "for everyone", with no break-glass exception.
Token and session
On success ZEUS issues a JWT HS256 (TTL 24 h by default) with the claims
email · tenant · role · via · jti. The frontend (NextAuth) keeps it on the session
and attaches it to every request as Authorization: Bearer <token>.
Who is logged in — active sessions
Each token has a unique jti, under which ZEUS registers the session in Redis
(email · role · IP · user-agent · login time · last_seen). The admin can see
who is currently logged in in the Roles & Theme → Active sessions studio:
a list of online users (seen < 5 min ago), with the ability to revoke.
GET /api/v1/admin/sessions → who is online (admin only)
POST /api/v1/admin/sessions/{jti}/revoke
POST /auth/logout → revoke your own session
With the ZEUS_SESSION_ENFORCE=1 flag, revoke = immediate logout; by default
it is a "visibility-only" view (the session disappears from the list, the token expires naturally).
In short: password → (2FA email) → JWT → session visible to the admin. If login "loops", first check the email and any lockout.