Skip to content

Support OAuth2/XOAUTH2 authentication for Gmail and other providers #2

@odrobnik

Description

@odrobnik

Problem

Post currently only supports username/password authentication stored in the keychain. Many modern email providers (Gmail, Outlook, Yahoo) are deprecating password-based IMAP access in favor of OAuth2.

SwiftMail already has XOAUTH2 support built in:

  • IMAPConnection.authenticateXOAUTH2(email:accessToken:)
  • IMAPServer.AuthenticationMethod.xoauth2(email:accessToken:)

But Post doesn't expose this to users.

Proposed Solution

Add OAuth2/XOAUTH2 support to Post's credential system:

1. Keychain Storage

Extend KeychainCredentialStore to support OAuth tokens:

// New storage method
func storeOAuth(id: String, host: String, port: Int, email: String, 
                accessToken: String, refreshToken: String?, 
                expiresAt: Date?) throws

// Retrieval includes token refresh logic
func oauthCredentials(forLabel id: String) throws -> OAuthCredentials?

Store OAuth credentials with:

  • Access token
  • Refresh token (for automatic renewal)
  • Expiry timestamp
  • Token endpoint URL

2. CLI Commands

# Interactive OAuth flow (opens browser)
post keychain add-oauth gmail --host imap.gmail.com --port 993 \
  --email you@gmail.com \
  --client-id YOUR_CLIENT_ID \
  --client-secret YOUR_SECRET

# Manual token entry (for CI/automation)
post keychain add-oauth gmail --host imap.gmail.com --port 993 \
  --email you@gmail.com \
  --access-token TOKEN \
  --refresh-token REFRESH_TOKEN

3. Token Refresh

Implement automatic token refresh before expiry:

  • Check token expiry on connection
  • Use refresh token to get new access token
  • Update keychain with new credentials
  • Transparent to the user

4. Configuration

Extend ServerConfiguration to indicate auth type:

{
  "servers": {
    "gmail": {
      "auth": "oauth2"  // vs "password" (default)
    }
  }
}

Or auto-detect from keychain credential type.

Benefits

  • ✅ Support modern email providers (Gmail, Outlook, Yahoo)
  • ✅ More secure than app-specific passwords
  • ✅ Automatic token refresh (no manual re-auth)
  • ✅ Future-proof as providers deprecate passwords
  • ✅ SwiftMail already has the foundation

Implementation Notes

  1. Token refresh: Use provider's token endpoint to refresh access tokens
  2. OAuth flow: Launch local web server for OAuth callback (port 8080)
  3. Storage: Keychain stores tokens with kSecAttrComment = "oauth" for type detection
  4. Backward compat: Existing password-based credentials continue working

Related Providers

  • Gmail: Requires OAuth2 for new apps
  • Outlook/Office 365: OAuth2 preferred
  • Yahoo Mail: OAuth2 required since 2020
  • ProtonMail Bridge: Still uses password (OK)

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions