|
| 1 | +# Domain-Wide Delegation Setup for Google Chat Notifications |
| 2 | + |
| 3 | +This guide explains how to enable **domain-wide delegation** so the Employee Portal can send proactive Google Chat messages to users (like Google Drive does). |
| 4 | + |
| 5 | +## Why Domain-Wide Delegation? |
| 6 | + |
| 7 | +Google Chat bots with service accounts cannot proactively send DM messages **UNLESS** they use domain-wide delegation to impersonate users. This is how Google Workspace apps like Drive, Calendar, etc. send you notifications. |
| 8 | + |
| 9 | +## Prerequisites |
| 10 | + |
| 11 | +- Google Workspace Admin access |
| 12 | +- Service account: `employee-portal-runtime@edvolution-admon.iam.gserviceaccount.com` |
| 13 | +- OAuth Client ID: `115131457162383560161` |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## Step 1: Enable Domain-Wide Delegation on Service Account |
| 18 | + |
| 19 | +1. Go to [Google Cloud Console - IAM & Admin - Service Accounts](https://console.cloud.google.com/iam-admin/serviceaccounts?project=edvolution-admon) |
| 20 | + |
| 21 | +2. Find service account: `employee-portal-runtime@edvolution-admon.iam.gserviceaccount.com` |
| 22 | + |
| 23 | +3. Click on the service account |
| 24 | + |
| 25 | +4. Go to **"Advanced Settings"** section |
| 26 | + |
| 27 | +5. Click **"Enable Google Workspace Domain-wide Delegation"** |
| 28 | + |
| 29 | +6. Save the OAuth2 Client ID: `115131457162383560161` |
| 30 | + |
| 31 | +--- |
| 32 | + |
| 33 | +## Step 2: Authorize API Scopes in Google Workspace Admin Console |
| 34 | + |
| 35 | +1. Go to [Google Workspace Admin Console](https://admin.google.com) |
| 36 | + |
| 37 | +2. Navigate to: **Security** → **Access and data control** → **API Controls** |
| 38 | + |
| 39 | +3. Click **"Manage Domain Wide Delegation"** |
| 40 | + |
| 41 | +4. Click **"Add new"** |
| 42 | + |
| 43 | +5. Enter the Client ID: `115131457162383560161` |
| 44 | + |
| 45 | +6. Add the following OAuth Scopes (comma-separated): |
| 46 | + ``` |
| 47 | + https://www.googleapis.com/auth/chat.messages,https://www.googleapis.com/auth/chat.spaces |
| 48 | + ``` |
| 49 | + |
| 50 | +7. Click **"Authorize"** |
| 51 | + |
| 52 | +--- |
| 53 | + |
| 54 | +## Step 3: Verify Configuration |
| 55 | + |
| 56 | +Run this test to verify domain-wide delegation works: |
| 57 | + |
| 58 | +```bash |
| 59 | +python3 << 'EOF' |
| 60 | +from google.oauth2 import service_account |
| 61 | +from googleapiclient.discovery import build |
| 62 | +
|
| 63 | +# This should be your service account credentials |
| 64 | +SCOPES = [ |
| 65 | + 'https://www.googleapis.com/auth/chat.messages', |
| 66 | + 'https://www.googleapis.com/auth/chat.spaces' |
| 67 | +] |
| 68 | +
|
| 69 | +# Test impersonation |
| 70 | +USER_EMAIL = 'dirk@edvolution.io' |
| 71 | +
|
| 72 | +try: |
| 73 | + from google.auth import default |
| 74 | + credentials, project = default(scopes=SCOPES) |
| 75 | +
|
| 76 | + if hasattr(credentials, 'with_subject'): |
| 77 | + delegated_creds = credentials.with_subject(USER_EMAIL) |
| 78 | + chat = build('chat', 'v1', credentials=delegated_creds) |
| 79 | + print(f"✅ Domain-wide delegation is configured correctly!") |
| 80 | + print(f" Service can impersonate: {USER_EMAIL}") |
| 81 | + else: |
| 82 | + print("❌ Credentials do not support domain-wide delegation") |
| 83 | + print(" Make sure you're using a service account with delegation enabled") |
| 84 | +except Exception as e: |
| 85 | + print(f"❌ Error: {e}") |
| 86 | + print(" Domain-wide delegation may not be set up correctly") |
| 87 | +EOF |
| 88 | +``` |
| 89 | + |
| 90 | +--- |
| 91 | + |
| 92 | +## Step 4: Update Application Code (Already Done) |
| 93 | + |
| 94 | +The code has been updated to support domain-wide delegation: |
| 95 | +- `NotificationService._get_chat_service(impersonate_user=email)` now supports impersonation |
| 96 | +- `send_approval_chat_card()` will use delegation when available |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +## Step 5: Test Proactive Notifications |
| 101 | + |
| 102 | +After completing setup, test by creating a time-off request: |
| 103 | + |
| 104 | +1. Log into the Employee Portal |
| 105 | +2. Create a time-off request |
| 106 | +3. The manager should receive: |
| 107 | + - ✅ Email notification (works now) |
| 108 | + - ✅ Google Chat DM (will work after domain-wide delegation) |
| 109 | + |
| 110 | +Check logs: |
| 111 | +```bash |
| 112 | +gcloud logging read 'resource.type=cloud_run_revision AND resource.labels.service_name=employee-portal AND textPayload=~"domain-wide delegation"' --limit 10 --format="table(timestamp,textPayload)" --freshness=1h |
| 113 | +``` |
| 114 | + |
| 115 | +--- |
| 116 | + |
| 117 | +## Security Considerations |
| 118 | + |
| 119 | +**Domain-wide delegation is powerful** - it allows the service account to act as any user in your domain. |
| 120 | + |
| 121 | +**Best practices:** |
| 122 | +1. ✅ Only grant minimum required scopes (`chat.messages`, `chat.spaces`) |
| 123 | +2. ✅ Limit to one service account |
| 124 | +3. ✅ Monitor usage via Cloud Logging |
| 125 | +4. ✅ Document who has access |
| 126 | +5. ✅ Review periodically |
| 127 | + |
| 128 | +**What the service can do:** |
| 129 | +- ✅ Send Chat messages on behalf of users |
| 130 | +- ✅ Create spaces on behalf of users |
| 131 | +- ❌ Cannot read messages (we didn't request that scope) |
| 132 | +- ❌ Cannot access other Google Workspace data (Drive, Gmail, etc.) |
| 133 | + |
| 134 | +--- |
| 135 | + |
| 136 | +## Troubleshooting |
| 137 | + |
| 138 | +### Error: "Request had insufficient authentication scopes" |
| 139 | +- Make sure you authorized the scopes in Admin Console (Step 2) |
| 140 | +- Wait 10-15 minutes for changes to propagate |
| 141 | + |
| 142 | +### Error: "Domain-wide delegation is not enabled" |
| 143 | +- Complete Step 1 to enable delegation on the service account |
| 144 | +- Redeploy the application |
| 145 | + |
| 146 | +### Still not working? |
| 147 | +1. Check Admin Console → Security → API Controls → Domain-wide delegation |
| 148 | +2. Verify Client ID matches: `115131457162383560161` |
| 149 | +3. Verify scopes are exactly: `https://www.googleapis.com/auth/chat.messages,https://www.googleapis.com/auth/chat.spaces` |
| 150 | +4. Check Cloud Run service account is `employee-portal-runtime@edvolution-admon.iam.gserviceaccount.com` |
| 151 | + |
| 152 | +--- |
| 153 | + |
| 154 | +## Alternative: Chat Space Instead of DMs |
| 155 | + |
| 156 | +If you prefer not to use domain-wide delegation, you can: |
| 157 | + |
| 158 | +1. **Create a Chat Space** (e.g., "HR Approvals") |
| 159 | +2. **Add all managers/admins** to the space |
| 160 | +3. **Add the bot** to the space |
| 161 | +4. **Send notifications to the space** instead of DMs |
| 162 | + |
| 163 | +This way: |
| 164 | +- ✅ No domain-wide delegation needed |
| 165 | +- ✅ All approvers see all requests |
| 166 | +- ✅ Transparent approval process |
| 167 | +- ❌ Less private (everyone sees everyone's requests) |
| 168 | + |
| 169 | +--- |
| 170 | + |
| 171 | +## Resources |
| 172 | + |
| 173 | +- [Domain-Wide Delegation Guide](https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority) |
| 174 | +- [Google Chat API - User Authentication](https://developers.google.com/workspace/chat/authenticate-authorize-chat-user) |
| 175 | +- [OAuth 2.0 Scopes for Google APIs](https://developers.google.com/identity/protocols/oauth2/scopes#chat) |
0 commit comments