Admin

Single Sign-On (SSO)

How SSO works between Opterius Panel and Opterius Mail, and how to configure it manually.

Last updated 2026-04-26
  • Automatic configuration (Opterius Panel installer)
  • Manual SSO setup
  • Testing SSO
  • Sending mail from an SSO session
  • Sent folder
  • Troubleshooting
  • Disabling SSO
  • Single Sign-On (SSO)

    When Opterius Mail is installed alongside Opterius Panel, users can open webmail directly from the Panel without re-entering their email password. This is Single Sign-On (SSO) — the Panel vouches for the user's identity and Opterius Mail trusts that voucher to open an IMAP session via Dovecot's master-user mechanism.

    How It Works

    1. User clicks "Open Webmail" for an account in Opterius Panel
             ↓
    2. Panel POSTs server-to-server to:
       {webmail_url}/sso/issue
       Body: { email, timestamp, signature }
             signature = HMAC-SHA256(secret, "{email}:{timestamp}")
             ↓
    3. Opterius Mail validates the HMAC + timestamp window (±60 s),
       generates a one-time random token (cached for 120 s),
       returns: { token, url: "{webmail_url}/sso/login?token=..." }
             ↓
    4. Panel redirects the user's browser to that URL
             ↓
    5. Opterius Mail receives the token at /sso/login:
       a. Looks up the email in cache (token is single-use, immediately consumed)
       b. Opens IMAP using the Dovecot master-user format:
          LOGIN "user@domain*vmail-master" "{IMAP_MASTER_PASS}"
       c. On success, flushes any prior session and establishes a fresh one
             ↓
    6. User lands in their inbox with no login prompt
    

    Security Properties

    Property Detail
    Server-to-server signed request Panel proves it knows the shared secret before any token exists. The user's browser never sees the secret.
    Token TTL 120 seconds. The single-use token cached on the webmail expires automatically.
    Single-use token The cache key is forgotten the moment the token is consumed at /sso/login. Replaying the URL returns "SSO token is invalid or has expired."
    Timestamp window The HMAC request must be within ±60 seconds of the webmail server's clock. Larger drift means NTP is broken on one side.
    Session isolation Before establishing the new SSO session, the webmail calls session()->flush() and session()->regenerate(true) to destroy any prior user's data. This prevents cross-account leakage when the same browser is used to switch between mailboxes.
    No password transmission The user's mail password is never sent over the wire. Authentication happens via Dovecot's master-user mechanism using IMAP_MASTER_PASS.

    Required configuration

    SSO needs both shared secrets and Dovecot's master-user mechanism configured.

    On the webmail side (/opt/opterius-mail/.env)

    PANEL_SSO_ENABLED=true
    PANEL_SSO_SECRET=<32+ char shared secret>
    
    IMAP_MASTER_USER=vmail-master
    IMAP_MASTER_PASS=<password from /etc/dovecot/master-users>
    

    On the panel side (/opt/opterius/.env)

    OPTERIUS_WEBMAIL_URL=http://your-server:8090
    OPTERIUS_WEBMAIL_SSO_SECRET=<same value as PANEL_SSO_SECRET above>
    

    The two secrets must be byte-identical. A single character difference causes every SSO attempt to fail with "Invalid signature."

    On Dovecot (/etc/dovecot/conf.d/auth-master.conf.ext)

    # Required: tells Dovecot to split "user@domain*master-user" into target + master.
    # Without this, the entire string is treated as a literal username and IMAP
    # login fails with AUTHENTICATIONFAILED.
    auth_master_user_separator = *
    
    passdb {
      driver = passwd-file
      master = yes
      args = /etc/dovecot/master-users
      result_success = continue
    }
    

    The master user file:

    echo "vmail-master:{plain}<random-32-hex-string>" > /etc/dovecot/master-users
    chown dovecot:dovecot /etc/dovecot/master-users
    chmod 640 /etc/dovecot/master-users
    systemctl restart dovecot
    

    Automatic configuration (Opterius Panel installer)

    When Opterius Mail is installed via the bundled installer or the retrofit script (_docs/install-opterius-mail.sh), all of the above is configured automatically:

    1. Generates a 32-character hex PANEL_SSO_SECRET.
    2. Writes it to both panel and mail .env files (matching values).
    3. Creates the Dovecot master user with a random password.
    4. Writes auth_master_user_separator = * and the master passdb block.
    5. Restarts Dovecot.

    The "Open Webmail" button works immediately after install — no manual steps.

    Manual SSO setup

    Only needed when reinstalling mail standalone or on a non-standard deployment.

    Step 1 — Generate a shared secret

    openssl rand -hex 32
    

    Step 2 — Write the secret on both sides

    # Webmail
    echo "PANEL_SSO_SECRET=<paste>"       >> /opt/opterius-mail/.env
    
    # Panel
    echo "OPTERIUS_WEBMAIL_SSO_SECRET=<paste>" >> /opt/opterius/.env
    echo "OPTERIUS_WEBMAIL_URL=http://<server>:8090" >> /opt/opterius/.env
    

    Step 3 — Set up the Dovecot master user

    DOVECOT_MASTER_PASS=$(openssl rand -hex 16)
    echo "vmail-master:{plain}${DOVECOT_MASTER_PASS}" > /etc/dovecot/master-users
    chown dovecot:dovecot /etc/dovecot/master-users
    chmod 640 /etc/dovecot/master-users
    
    cat > /etc/dovecot/conf.d/auth-master.conf.ext <<'EOF'
    auth_master_user_separator = *
    
    passdb {
      driver = passwd-file
      master = yes
      args = /etc/dovecot/master-users
      result_success = continue
    }
    EOF
    
    # Make sure 10-auth.conf includes it
    grep -q "auth-master.conf.ext" /etc/dovecot/conf.d/10-auth.conf || \
        echo '!include auth-master.conf.ext' >> /etc/dovecot/conf.d/10-auth.conf
    
    systemctl restart dovecot
    

    Step 4 — Wire the master credentials into the webmail

    # /opt/opterius-mail/.env
    IMAP_MASTER_USER=vmail-master
    IMAP_MASTER_PASS=<the DOVECOT_MASTER_PASS from above>
    

    Step 5 — Clear caches

    cd /opt/opterius-mail && php artisan config:clear
    cd /opt/opterius      && php artisan config:clear
    

    Testing SSO

    # 1. End-to-end via the panel
    # Log into the panel, click Email → Open Webmail next to any account.
    # You should land in the inbox.
    
    # 2. Verify Dovecot master auth at the protocol level
    {
      printf 'a1 LOGIN "user@example.com*vmail-master" "<master-pass>"\r\n'
      sleep 1
      printf 'a2 LOGOUT\r\n'
    } | nc -q2 127.0.0.1 143
    # Expected: a1 OK Logged in
    

    Sending mail from an SSO session

    The user's real mail password is not in the SSO session — only the master password is. So when the user composes and sends a message, the webmail submits via SMTP using the same master-user format:

    SMTP AUTH LOGIN
    username: user@example.com*vmail-master
    password: <master-pass>
    

    Postfix delegates this to Dovecot SASL, which understands the master separator (same auth_master_user_separator = * setting). If SMTP fails with 535 authentication failed for SSO sessions only, that's the missing setting.

    Sent folder

    Opterius Mail's ComposeController::send() automatically APPENDs the sent message to the user's Sent folder via IMAP after successful SMTP delivery. The folder is auto-created on first use, with \Sent SPECIAL-USE attribute when the server supports it. Failure to APPEND is silent (delivery has already happened) and logged at warning level.

    Troubleshooting

    "could not authenticate with mail server" on the SSO login page

    The SSO request was valid but Dovecot rejected the master-user IMAP login. Most common: auth_master_user_separator = * is missing. Verify with:

    doveconf -n | grep separator
    # Should print: auth_master_user_separator = *
    

    If empty, add the setting (see Step 3 above) and restart Dovecot.

    A real-IMAP-login test confirms it:

    { printf 'a1 LOGIN "user@example.com*vmail-master" "<master-pass>"\r\n'; sleep 1; printf 'a2 LOGOUT\r\n'; } | nc -q2 127.0.0.1 143
    

    a1 NO [AUTHENTICATIONFAILED] means the setting isn't applied or the master pass doesn't match /etc/dovecot/master-users.

    "Invalid signature" (403) on /sso/issue

    The HMAC didn't verify. Either the secrets don't match, or the timestamp drifted. Check both .env files contain the same secret string (no trailing whitespace), and that NTP is running on both ends.

    timedatectl status                # both servers
    diff <(grep -oP 'PANEL_SSO_SECRET=\K.*' /opt/opterius-mail/.env) \
         <(grep -oP 'OPTERIUS_WEBMAIL_SSO_SECRET=\K.*' /opt/opterius/.env)
    

    The diff should be empty.

    "SSO token is invalid or has expired"

    The token was already used (single-use), or more than 120 s passed between issuance and the user clicking through. Generate a fresh link.

    Wrong inbox loads after switching accounts

    Pre-2026-04-26 versions of Opterius Mail had a session-leakage bug where stale data from the previous SSO login could surface the wrong mailbox. Fixed by session()->flush() + session()->regenerate(true) before establishing the new session. If you're seeing this, update Opterius Mail (cd /opt/opterius-mail && git pull && php artisan config:clear).

    SMTP 535 authentication failed only on SSO sessions

    Postfix's SASL backend (Dovecot) needs the same auth_master_user_separator = * setting that IMAP uses. This is the same fix as the IMAP issue above; both auth paths share the Dovecot config.

    Disabling SSO

    Set PANEL_SSO_ENABLED=false in /opt/opterius-mail/.env and clear cache:

    sed -i 's/^PANEL_SSO_ENABLED=.*/PANEL_SSO_ENABLED=false/' /opt/opterius-mail/.env
    cd /opt/opterius-mail && php artisan config:clear
    

    The /sso/issue and /sso/login routes will return 403. Users will see the standard login page when they click "Open Webmail."