-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
🔖 Feature description
Add support for unified email accounts where users can access their account through any authentication provider (Google, GitHub, email/password, etc.) as long as they use the same email address. This feature is controlled by a new environment variable UNIFIED_EMAIL_ACCOUNTS and is opt-in to maintain backward compatibility.
Key capabilities:
- OAuth users (Google, GitHub, etc.) can sign in to existing email/password accounts
- Email/password users can sign in via OAuth providers
- OAuth-only users can add a password to their account (with email verification for security)
- Password reset works for any account that has a password set
- Auto-activation when OAuth provider verifies the email
🎤 Why is this feature needed ?
Problem Statement
Currently, Postiz treats each provider + email combination as a separate account. This creates friction:
- User registered with email/password, later tries Google OAuth: Gets redirected to sign-up page instead of logging in, even though the email is the same
- User registered with Google OAuth, wants to add password: Cannot add password login capability
- Self-hosted instances with registration disabled: OAuth users with matching emails cannot access their existing accounts
Use Cases
Use Case 1: Enterprise SSO Migration
A company using email/password wants to add Google Workspace SSO. Current behavior forces users to create new accounts or maintain two separate accounts.
Use Case 2: Flexibility for End Users
Users may prefer different login methods at different times (OAuth on mobile, password on shared computers). Unified accounts allow this seamlessly.
Use Case 3: Account Recovery
If an OAuth provider has issues, users with unified accounts can still access via password (if set).
Security Considerations
- Email verification is required when an OAuth user adds a password (prevents account hijacking)
- Password hash is stored in JWT token during verification flow (never exposed, uses bcrypt with salt)
- Feature is opt-in via environment variable to prevent unexpected behavior changes
✌️ How do you aim to achieve this?
Implementation Approach
1. New Environment Variable
UNIFIED_EMAIL_ACCOUNTS=true # Default: false (disabled)2. Database Layer
- New method
getUserByEmailAnyProvider(email)- finds user by email regardless of provider - New method
setPassword(id, password)- sets password for any account - New method
setPasswordHash(id, hash)- sets pre-hashed password (for verification flow)
3. Authentication Flows Modified
| Scenario | Flag OFF (Original) | Flag ON (New) |
|---|---|---|
| OAuth login, email exists as LOCAL | Redirect to sign-up | Log in to existing account |
| LOCAL registration, email exists as OAuth | Error: "Email exists" | Send verification email to add password |
| Password reset for OAuth-only user | Silent fail (no email sent) | Return message explaining OAuth-only account |
| OAuth login for unactivated LOCAL user | Redirect to sign-up | Auto-activate and log in |
4. Secure Password Addition Flow
1. OAuth user tries to register with email/password
2. System finds existing OAuth account with same email
3. JWT created with: { id, email, passwordHash (bcrypt), type: 'add-password' }
4. Verification email sent with activation link
5. User clicks link → password saved to database
6. User can now log in via email/password OR OAuth
5. Files Modified
auth.service.ts- Core authentication logic with flag checksauth.controller.ts- Uses service'sactivationRequiredresponseusers.repository.ts- New database methodsusers.service.ts- Exposed new repository methods.env.example- Documentation for new variable
🔄️ Additional Information
Backward Compatibility
- 100% backward compatible when
UNIFIED_EMAIL_ACCOUNTSis not set or set tofalse - All existing flows work exactly as before
- No database migrations required
- No breaking changes to API contracts
Alternative Solutions Considered
-
Automatic account linking without verification: Rejected due to security risk (anyone knowing an email could hijack OAuth accounts)
-
Separate "link accounts" UI flow: More complex, requires frontend changes, and still needs the backend capability we're implementing
-
Always-on unified emails: Rejected to maintain backward compatibility and let self-hosters choose their security model
Testing Recommendations
- Test with
UNIFIED_EMAIL_ACCOUNTS=falseto verify no regression - Test with
UNIFIED_EMAIL_ACCOUNTS=true:- OAuth → existing LOCAL account
- LOCAL registration → existing OAuth account (verify email flow)
- Password reset for OAuth-only user
- Password reset for account with password
- Auto-activation for unactivated LOCAL user via OAuth
Related
- Useful for self-hosted instances with multiple auth providers
- Complements existing OAuth provider support (Google, GitHub, Generic OAuth)
👀 Have you spent some time to check if this feature request has been raised before?
- I checked and didn't find similar issue
Are you willing to submit PR?
Yes I am willing to submit a PR!