Skip to main content

OAuth Configuration Guide

This comprehensive guide covers OAuth authentication for connecting Gmail and Outlook accounts to EDITH for email sending and receiving.


Overview

OAuth integration allows your users to connect their personal email accounts (Gmail, Outlook) to send and receive emails through EDITH. This is essential for:

  • Personal email integration - Users can send from their own email addresses
  • IMAP monitoring - Automatically fetch incoming emails
  • Reply tracking - Monitor and process email replies
  • Calendar access - Some providers support calendar integration

Supported Providers:

  • 🔵 Google (Gmail, Google Workspace)
  • 🟦 Microsoft (Outlook, Office 365, Hotmail)

Prerequisites

Before implementing OAuth, you need:

  1. Cloud App Registration - Register your app with Google/Microsoft
  2. OAuth Credentials - Obtain Client ID and Client Secret
  3. Redirect URIs - Configure callback URLs
  4. Scopes/Permissions - Request necessary email permissions

Part 1: Cloud App Registration

Register with Google (Gmail)

Step 1: Create Google Cloud Project

  1. Go to Google Cloud Console
  2. Create a new project or select existing
  3. Project name: YourApp Email Integration

Step 2: Enable Gmail API

  1. Navigate to APIs & ServicesLibrary
  2. Search for Gmail API
  3. Click Enable
  1. Go to APIs & ServicesOAuth consent screen
  2. Choose External (for public use) or Internal (for workspace only)
  3. Fill in required information:
    • App name: Your application name
    • User support email: Your support email
    • Developer contact: Your email
  4. Add scopes:
    • https://www.googleapis.com/auth/gmail.send - Send emails
    • https://www.googleapis.com/auth/gmail.readonly - Read emails
    • https://www.googleapis.com/auth/gmail.modify - Modify emails (labels)
  5. Save and continue

Step 4: Create OAuth Credentials

  1. Go to APIs & ServicesCredentials
  2. Click Create CredentialsOAuth client ID
  3. Application type: Web application
  4. Add Authorized redirect URIs:
    https://api.sparrowmailer.com/oauth/token
  5. Click Create
  6. Save the Client ID and Client Secret - you'll need these!

Example Credentials:

{
"client_id": "123456789-abcdefg.apps.googleusercontent.com",
"client_secret": "GOCSPX-abc123xyz789",
"redirect_uris": ["https://api.sparrowmailer.com/oauth/token"]
}

Register with Microsoft (Outlook)

Step 1: Go to Azure Portal

  1. Visit Azure Portal
  2. Navigate to Azure Active Directory
  3. Select App registrations

Step 2: Register Application

  1. Click New registration
  2. Fill in details:
    • Name: Your application name
    • Supported account types: Choose appropriate option
      • Personal Microsoft accounts only - For Outlook/Hotmail
      • Accounts in any organizational directory - For Office 365
      • All Microsoft accounts - For both
  3. Redirect URI:
    • Platform: Web
    • URI: https://api.sparrowmailer.com/oauth/token
  4. Click Register

Step 3: Configure API Permissions

  1. Go to API permissions
  2. Click Add a permission
  3. Select Microsoft Graph
  4. Choose Delegated permissions
  5. Add required permissions:
    • Mail.Send - Send emails
    • Mail.Read - Read emails
    • Mail.ReadWrite - Modify emails
    • IMAP.AccessAsUser.All - IMAP access
    • SMTP.Send - SMTP sending
  6. Click Grant admin consent (if you have admin rights)

Step 4: Create Client Secret

  1. Go to Certificates & secrets
  2. Click New client secret
  3. Description: EDITH OAuth Secret
  4. Expiration: Choose duration (24 months recommended)
  5. Click Add
  6. Copy the secret value immediately - it won't be shown again!

Example Credentials:

{
"client_id": "12345678-1234-1234-1234-123456789abc",
"client_secret": "abc~123XYZ-secretValue",
"tenant_id": "common",
"redirect_uri": "https://api.sparrowmailer.com/oauth/token"
}

Part 2: Register Cloud App in EDITH

After obtaining OAuth credentials from Google/Microsoft, register them in EDITH.

Endpoint

POST /v1/cloudapp/create

Request Body

FieldTypeRequiredDescription
providerstring✅ YesOAuth provider: "google" or "microsoft"
client_idstring✅ YesOAuth Client ID from provider
client_secretstring✅ YesOAuth Client Secret from provider
redirect_uristring✅ YesCallback URL: https://api.sparrowmailer.com/oauth/token
scopesstring[]✅ YesArray of OAuth scopes/permissions (see below)
app_namestringNoFriendly name for this app configuration

Required Scopes by Connection Type

Google (Gmail)

For SMTP (Sending only):

"scopes": [
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
]

For IMAP (Receiving only):

"scopes": [
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
]

For SMTP_IMAP (Both):

"scopes": [
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile"
]

Microsoft (Outlook)

For SMTP (Sending only):

"scopes": [
"https://graph.microsoft.com/Mail.Send",
"email",
"offline_access",
"openid",
"profile"
]

For IMAP (Receiving only):

"scopes": [
"https://graph.microsoft.com/Mail.Read",
"https://graph.microsoft.com/Mail.ReadBasic",
"https://graph.microsoft.com/Mail.ReadWrite",
"https://graph.microsoft.com/User.Read",
"email",
"openid",
"offline_access",
"profile"
]

For SMTP_IMAP (Both):

"scopes": [
"https://graph.microsoft.com/Mail.Read",
"https://graph.microsoft.com/Mail.ReadBasic",
"https://graph.microsoft.com/Mail.ReadWrite",
"https://graph.microsoft.com/Mail.Send",
"https://graph.microsoft.com/User.Read",
"email",
"openid",
"offline_access",
"profile"
]

Example: Register Gmail App

curl -X POST https://api.edith.example.com/v1/cloudapp/create \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"app_name": "My App Gmail Integration",
"client_id": "123456789-abcdefg.apps.googleusercontent.com",
"client_secret": "GOCSPX-abc123xyz789",
"redirect_uri": "https://api.edith.example.com/oauth/google/callback",
"scopes": [
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.modify"
]
}'

Response

{
"success": true,
"app_id": "cloudapp_abc123xyz",
"message": "Cloud app registered successfully"
}

Save the app_id - you'll use it for OAuth login!


Example: Register Outlook App

curl -X POST https://api.edith.example.com/v1/cloudapp/create \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"provider": "microsoft",
"app_name": "My App Outlook Integration",
"client_id": "12345678-1234-1234-1234-123456789abc",
"client_secret": "abc~123XYZ-secretValue",
"redirect_uri": "https://api.edith.example.com/oauth/microsoft/callback",
"scopes": [
"https://outlook.office.com/Mail.Send",
"https://outlook.office.com/Mail.Read",
"https://outlook.office.com/IMAP.AccessAsUser.All",
"https://outlook.office.com/SMTP.Send"
]
}'

Part 3: OAuth Flows

EDITH supports two OAuth authentication flows:

Flow 1: New OAuth Flow (User Login)

Use this when users need to grant permission for the first time.

Process:

  1. Your app calls /v1/oauth/login with exchange_token: false
  2. EDITH returns OAuth authorization URL
  3. Redirect user to this URL
  4. User logs in and grants permissions
  5. Provider redirects back to EDITH with authorization code
  6. EDITH exchanges code for tokens
  7. EDITH creates email configuration
  8. User redirected to your app with success parameters
  9. Your app calls /v1/oauth/active to activate the connection

Request Example

curl -X POST https://api.edith.example.com/v1/oauth/login \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"app_id": "cloudapp_abc123xyz",
"type": "smtp_imap",
"exchange_token": false,
"webhook": {
"url": "https://yourapp.com/webhooks/incoming-email",
"method": "POST",
"headers": {
"X-Webhook-Secret": "your-secret"
}
},
"state": "user_123_session_xyz"
}'

Response

{
"success": true,
"url": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=...&scope=...&state=..."
}

Redirect user to this URL!

User Authorization

User sees Google/Microsoft login page → Grants permissions → Redirected back

Callback Parameters

After successful OAuth, user is redirected to your app:

https://yourapp.com/oauth/callback?
email=user@gmail.com&
mailer_id=mailer_abc123&
verified=true&
message=success&
state=user_123_session_xyz
ParameterDescription
emailUser's authenticated email address
mailer_idEDITH mailer configuration ID
verifiedtrue if successful, false if failed
messageSuccess message or error details
stateYour custom state (for tracking user/session)
errorPresent only on failure

Activate Connection

curl -X PUT https://api.edith.example.com/v1/oauth/active \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"mailer_id": "mailer_abc123",
"active": true
}'

Flow 2: Token Exchange Flow (Existing Tokens)

Use this when you already have OAuth tokens and want to create/update EDITH configuration.

When to use:

  • Migrating from another email service
  • You've already obtained tokens through your own OAuth flow
  • Refreshing expired configurations

Process:

  1. Your app calls /v1/oauth/login with exchange_token: true
  2. Provide existing access_token and refresh_token
  3. EDITH validates tokens with provider
  4. EDITH creates/updates email configuration
  5. Returns success response (no redirect)

Request Example

curl -X POST https://api.edith.example.com/v1/oauth/login \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"app_id": "cloudapp_abc123xyz",
"mailer_id": "existing_mailer_id",
"type": "smtp_imap",
"exchange_token": true,
"token": {
"access_token": "ya29.a0AfB_byDxxx...",
"refresh_token": "1//0gL9xyz...",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "https://www.googleapis.com/auth/gmail.send https://www.googleapis.com/auth/gmail.readonly",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjU5N..."
},
"webhook": {
"url": "https://yourapp.com/webhooks/incoming",
"method": "POST",
"headers": {}
}
}'

Token Fields Explained

FieldRequiredDescription
access_token✅ YesOAuth access token (short-lived, ~1 hour)
refresh_token✅ YesOAuth refresh token (used to get new access tokens)
expires_in✅ YesAccess token expiration in seconds (typically 3600)
token_type✅ YesUsually "Bearer"
scope✅ YesSpace-separated list of granted permissions
id_tokenNoJWT identity token (optional, contains user info)

Response

{
"success": true,
"mailer_id": "mailer_abc123",
"message": "Email configuration updated successfully"
}

No redirect - configuration is immediately active!


Part 4: Connection Types

Choose the appropriate connection type based on your needs:

TypeDescriptionUse Case
smtpSending onlyOne-way email sending (notifications, alerts)
imapReceiving onlyMonitor inbox for replies (no sending)
smtp_imapBoth sending and receivingFull bidirectional email communication

SMTP Only (smtp)

{
"type": "smtp",
"app_id": "cloudapp_abc123xyz"
}

Use cases:

  • Transactional emails
  • Notifications
  • Alerts
  • One-way communication

Limitations:

  • Cannot receive/monitor incoming emails
  • No reply tracking

IMAP Only (imap)

{
"type": "imap",
"app_id": "cloudapp_abc123xyz",
"webhook": {
"url": "https://yourapp.com/webhooks/incoming",
"method": "POST"
}
}

Use cases:

  • Reply monitoring
  • Inbox automation
  • Email parsing
  • Support ticket systems

Requirements:

  • Webhook URL is required
  • EDITH monitors inbox and sends new emails to your webhook

Limitations:

  • Cannot send emails

SMTP + IMAP (smtp_imap)

{
"type": "smtp_imap",
"app_id": "cloudapp_abc123xyz",
"webhook": {
"url": "https://yourapp.com/webhooks/incoming",
"method": "POST"
}
}

Use cases:

  • Full email conversations
  • Support systems
  • CRM integrations
  • Two-way communication

Features:

  • Send emails via SMTP
  • Monitor inbox via IMAP
  • Receive webhooks for incoming emails
  • Full threading support

⭐ Recommended for most applications!


Part 5: Labels (Gmail) / Folders (Outlook)

Labels help organize and filter incoming emails.

How Labels Work

Gmail:

  • Uses labels system (multiple labels per email)
  • Common labels: INBOX, SENT, DRAFT, SPAM, TRASH
  • Custom labels: User-created categories

Outlook:

  • Uses folders system (one folder per email)
  • Common folders: Inbox, Sent Items, Drafts, Junk Email
  • Custom folders: User-created folders

EDITH Label Handling

When EDITH fetches emails, it includes label information:

{
"event": "INCOMING_EMAIL",
"details": {
"from": "customer@example.com",
"subject": "Re: Support inquiry",
"label-ids": ["INBOX", "UNREAD"],
"body-html": "...",
"mailer-service": "gmail"
}
}

Common Gmail Labels

LabelDescription
INBOXMain inbox
SENTSent emails
DRAFTDraft emails
SPAMSpam/junk emails
TRASHDeleted emails
UNREADUnread marker
STARREDStarred/flagged
IMPORTANTMarked as important

Filtering by Label

You can filter which emails to process based on labels:

// In your webhook handler
app.post('/webhooks/incoming', (req, res) => {
const { details } = req.body;
const labels = details['label-ids'] || [];

// Only process inbox emails
if (labels.includes('INBOX')) {
// Process email
processEmail(details);
}

// Ignore spam
if (labels.includes('SPAM')) {
console.log('Ignoring spam email');
return res.status(200).json({ received: true });
}

// Handle sent emails differently
if (labels.includes('SENT')) {
// Track sent emails
trackSentEmail(details);
}

res.status(200).json({ received: true });
});

Label Monitoring Configuration

By default, EDITH monitors:

  • INBOX - All incoming emails
  • Excludes SPAM, TRASH automatically

Custom Label Monitoring (coming soon):

{
"type": "imap",
"monitor_labels": ["INBOX", "CUSTOM_LABEL"],
"exclude_labels": ["SPAM", "TRASH", "PROMOTIONS"]
}

Part 6: Token Management

Token Lifecycle

Access Token:

  • Short-lived (~1 hour)
  • Used for API requests
  • Automatically refreshed by EDITH

Refresh Token:

  • Long-lived (no expiration for Google, 90 days for Microsoft)
  • Used to obtain new access tokens
  • Stored securely by EDITH

Automatic Token Refresh

EDITH automatically handles token refresh:

  1. Access token expires
  2. EDITH detects expiration
  3. Uses refresh token to get new access token
  4. Updates configuration
  5. Continues operations seamlessly

You don't need to worry about token refresh!

Token Revocation

Users can revoke access at any time:

Gmail:

Outlook:

When revoked:

  • EDITH receives authentication errors
  • Connection becomes inactive
  • User must re-authenticate

Handling Revoked Tokens

// Webhook payload when OAuth fails
{
"event": "OAUTH_ERROR",
"details": {
"mailer_id": "mailer_abc123",
"email": "user@gmail.com",
"error": "invalid_grant",
"message": "Token has been revoked"
}
}

Action: Prompt user to reconnect their account


Part 7: Complete Integration Example

Frontend Integration (React)

import React, { useState } from 'react';

function EmailConnection() {
const [loading, setLoading] = useState(false);

const connectGmail = async () => {
setLoading(true);

try {
// Call your backend
const response = await fetch('/api/oauth/initiate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
provider: 'google',
connection_type: 'smtp_imap'
})
});

const data = await response.json();

if (data.success && data.oauth_url) {
// Redirect to OAuth URL
window.location.href = data.oauth_url;
}
} catch (error) {
console.error('OAuth error:', error);
setLoading(false);
}
};

return (
<div>
<h2>Connect Your Email</h2>
<button onClick={connectGmail} disabled={loading}>
{loading ? 'Connecting...' : 'Connect Gmail'}
</button>
</div>
);
}

Backend Integration (Node.js/Express)

const express = require('express');
const axios = require('axios');
const app = express();

// Initiate OAuth
app.post('/api/oauth/initiate', async (req, res) => {
const { provider, connection_type } = req.body;
const userId = req.user.id; // From your auth middleware

try {
// Call EDITH OAuth API
const response = await axios.post(
'https://api.edith.example.com/v1/oauth/login',
{
app_id: process.env.CLOUD_APP_ID,
type: connection_type,
exchange_token: false,
webhook: {
url: `${process.env.APP_URL}/webhooks/incoming-email`,
method: 'POST',
headers: {
'X-Webhook-Secret': process.env.WEBHOOK_SECRET
}
},
state: Buffer.from(JSON.stringify({ userId })).toString('base64')
},
{
headers: {
'Authorization': `Bearer ${process.env.EDITH_API_TOKEN}`,
'Content-Type': 'application/json'
}
}
);

res.json({
success: true,
oauth_url: response.data.url
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});

// OAuth callback handler
app.get('/oauth/callback', async (req, res) => {
const { email, mailer_id, verified, state } = req.query;

if (!verified) {
return res.redirect('/oauth/error?message=Connection failed');
}

// Decode state to get user ID
const { userId } = JSON.parse(Buffer.from(state, 'base64').toString());

// Activate the connection
try {
await axios.put(
'https://api.edith.example.com/v1/oauth/active',
{ mailer_id, active: true },
{
headers: {
'Authorization': `Bearer ${process.env.EDITH_API_TOKEN}`,
'Content-Type': 'application/json'
}
}
);

// Save to your database
await db.emailConnections.create({
userId,
email,
mailerId: mailer_id,
provider: 'gmail',
active: true
});

res.redirect('/oauth/success');
} catch (error) {
res.redirect('/oauth/error?message=Activation failed');
}
});

// Webhook handler
app.post('/webhooks/incoming-email', (req, res) => {
// Verify webhook secret
if (req.headers['x-webhook-secret'] !== process.env.WEBHOOK_SECRET) {
return res.status(401).send('Unauthorized');
}

const { event, details } = req.body;

if (event === 'INCOMING_EMAIL') {
// Process incoming email
console.log('New email from:', details.from);
console.log('Subject:', details.subject);
console.log('Labels:', details['label-ids']);

// Your business logic here
processIncomingEmail(details);
}

res.status(200).json({ received: true });
});

Best Practices

Security

  1. Store secrets securely - Use environment variables, never hardcode
  2. Validate webhooks - Always check webhook secrets
  3. Use HTTPS - All redirect URIs must be HTTPS
  4. Encrypt tokens - If storing tokens, encrypt them
  5. Limit scopes - Only request necessary permissions

User Experience

  1. Clear permissions - Explain why you need email access
  2. Handle errors gracefully - Show helpful error messages
  3. Allow reconnection - Let users reconnect if tokens expire
  4. Status indicators - Show connection status in UI
  5. Revocation handling - Detect and handle revoked access

Implementation

  1. Use state parameter - Track user/session across OAuth flow
  2. Handle timeouts - OAuth flow can take time
  3. Test thoroughly - Test with multiple accounts
  4. Monitor webhooks - Log and monitor webhook deliveries
  5. Implement retries - Handle temporary failures

Troubleshooting

IssueCauseSolution
invalid_clientWrong client ID/secretVerify cloud app credentials
redirect_uri_mismatchRedirect URI doesn't matchCheck cloud app configuration
invalid_grantToken expired/revokedUser must re-authenticate
insufficient_scopeMissing permissionsUpdate scopes in cloud app
access_deniedUser denied permissionUser refused access
Webhook not receivingWrong URL or headersVerify webhook configuration
Token refresh failedRefresh token invalidUser must reconnect

API Reference Summary

Register Cloud App

POST /v1/cloudapp/create

Initiate OAuth

POST /v1/oauth/login

Activate Connection

PUT /v1/oauth/active

Get OAuth Config

GET /v1/oauth/config

For detailed API specifications, see the API Reference