Cocoanetics / Cocoanetics/Post

Support OAuth2/XOAUTH2 authentication for Gmail and other providers

Open
#2 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Swift
Stars
5
Forks
0
PR merge metrics
No merged PRs in 30d

Description

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

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing KeychainCredentialStore, ServerConfiguration, and the existing keychain CLI commands, then compare their credential flow with SwiftMail's IMAPConnection.authenticateXOAUTH2 and IMAPServer.AuthenticationMethod.xoauth2 APIs. Done means OAuth credentials can be stored and retrieved, the add-oauth commands support the described flows, token refresh is handled, and existing password authentication remains compatible.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
authentication, backend, cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.