Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion apps/docs/content/docs/en/self-hosting/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,48 @@ import { Callout } from 'fumadocs-ui/components/callout'
| `API_ENCRYPTION_KEY` | Encrypts stored API keys (32 hex chars): `openssl rand -hex 32` |
| `COPILOT_API_KEY` | API key for copilot features |
| `ADMIN_API_KEY` | Admin API key for GitOps operations |
| `RESEND_API_KEY` | Email service for notifications |
| `ALLOWED_LOGIN_DOMAINS` | Restrict signups to domains (comma-separated) |
| `ALLOWED_LOGIN_EMAILS` | Restrict signups to specific emails (comma-separated) |
| `DISABLE_REGISTRATION` | Set to `true` to disable new user signups |

## Email Providers

Configure one provider — the mailer auto-detects in priority order: **Resend → AWS SES → SMTP → Azure Communication Services**. If none are configured, emails are logged to the console instead.

| Variable | Description |
|----------|-------------|
| `FROM_EMAIL_ADDRESS` | Sender address (e.g. `Sim <noreply@example.com>`). Falls back to `noreply@EMAIL_DOMAIN`. |
| `EMAIL_DOMAIN` | Default domain when `FROM_EMAIL_ADDRESS` is unset |
| `EMAIL_VERIFICATION_ENABLED` | Set to `true` to require email verification on signup |

**Resend**

| Variable | Description |
|----------|-------------|
| `RESEND_API_KEY` | API key from [resend.com](https://resend.com) |

**AWS SES**

| Variable | Description |
|----------|-------------|
| `AWS_SES_REGION` | AWS region for SES (e.g. `us-east-1`). Credentials are resolved through the standard AWS SDK provider chain (env vars, IRSA, ECS/EC2 instance role, SSO). |

**SMTP** (works with MailHog, Postfix, SendGrid SMTP, etc.)

| Variable | Description |
|----------|-------------|
| `SMTP_HOST` | SMTP server hostname |
| `SMTP_PORT` | `465` for implicit TLS, `587` for STARTTLS, `25` for plain |
| `SMTP_USER` | Optional — omit for unauthenticated relays |
| `SMTP_PASS` | Optional — omit for unauthenticated relays |
| `SMTP_SECURE` | Set to `true` to force TLS on connect; auto-true on port 465 |

**Azure Communication Services**

| Variable | Description |
|----------|-------------|
| `AZURE_ACS_CONNECTION_STRING` | Azure Communication Services connection string |

## Example .env

```bash
Expand Down
1,139 changes: 22 additions & 1,117 deletions apps/docs/content/docs/en/triggers/hubspot.mdx

Large diffs are not rendered by default.

26 changes: 24 additions & 2 deletions apps/sim/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,30 @@ INTERNAL_API_SECRET=your_internal_api_secret # Use `openssl rand -hex 32` to gen
API_ENCRYPTION_KEY=your_api_encryption_key # Use `openssl rand -hex 32` to generate, used to encrypt api keys

# Email Provider (Optional)
# RESEND_API_KEY= # Uncomment and add your key from https://resend.com to send actual emails
# If left commented out, emails will be logged to console instead
# Configure ONE provider — the mailer auto-detects in priority order:
# Resend → AWS SES → SMTP → Azure Communication Services. If none are
# configured, emails are logged to console instead.
#
# Resend
# RESEND_API_KEY= # API key from https://resend.com
#
# AWS SES (credentials resolved via the standard AWS provider chain:
# env vars, shared config, ECS/EKS task role, EC2 instance profile, SSO)
# AWS_SES_REGION=us-east-1
#
# SMTP (works with MailHog locally: host=localhost port=1025, no auth)
# SMTP_HOST=smtp.example.com
# SMTP_PORT=587 # 465 = implicit TLS, 587 = STARTTLS, 25 = plain
# SMTP_USER= # Optional — omit for unauthenticated relays
# SMTP_PASS= # Optional — omit for unauthenticated relays
# SMTP_SECURE= # Set "true" to force TLS on connect; auto-true on port 465
#
# Azure Communication Services
# AZURE_ACS_CONNECTION_STRING=
#
# Shared sender configuration
# FROM_EMAIL_ADDRESS="Sim <noreply@example.com>"
# EMAIL_DOMAIN=example.com # Fallback when FROM_EMAIL_ADDRESS is unset

# Local AI Models (Optional)
# OLLAMA_URL=http://localhost:11434 # URL for local Ollama server - uncomment if using local models
Expand Down
22 changes: 20 additions & 2 deletions apps/sim/app/api/auth/oauth/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,18 @@
* @vitest-environment node
*/

import { redisConfigMock, redisConfigMockFns } from '@sim/testing'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

vi.mock('@/lib/oauth/oauth', () => ({
refreshOAuthToken: vi.fn(),
OAUTH_PROVIDERS: {},
}))

vi.mock('@/lib/core/config/redis', () => redisConfigMock)

import { db } from '@sim/db'
import { __resetCoalesceLocallyForTests } from '@/lib/concurrency/singleflight'
import { refreshOAuthToken } from '@/lib/oauth'
import {
getCredential,
Expand Down Expand Up @@ -49,6 +53,10 @@ function mockUpdateChain() {
describe('OAuth Utils', () => {
beforeEach(() => {
vi.clearAllMocks()
__resetCoalesceLocallyForTests()
redisConfigMockFns.mockGetRedisClient.mockReturnValue(null)
redisConfigMockFns.mockAcquireLock.mockResolvedValue(true)
redisConfigMockFns.mockReleaseLock.mockResolvedValue(true)
})

afterEach(() => {
Expand Down Expand Up @@ -107,6 +115,7 @@ describe('OAuth Utils', () => {
}

mockRefreshOAuthToken.mockResolvedValueOnce({
ok: true,
accessToken: 'new-token',
expiresIn: 3600,
refreshToken: 'new-refresh-token',
Expand All @@ -130,7 +139,11 @@ describe('OAuth Utils', () => {
providerId: 'google',
}

mockRefreshOAuthToken.mockResolvedValueOnce(null)
mockRefreshOAuthToken.mockResolvedValueOnce({
ok: false,
errorCode: 'invalid_grant',
message: 'Failed',
})

await expect(
refreshTokenIfNeeded('request-id', mockCredential, 'credential-id')
Expand Down Expand Up @@ -198,6 +211,7 @@ describe('OAuth Utils', () => {
mockUpdateChain()

mockRefreshOAuthToken.mockResolvedValueOnce({
ok: true,
accessToken: 'new-token',
expiresIn: 3600,
refreshToken: 'new-refresh-token',
Expand Down Expand Up @@ -237,7 +251,11 @@ describe('OAuth Utils', () => {
mockSelectChain([mockResolvedCredential])
mockSelectChain([mockAccountRow])

mockRefreshOAuthToken.mockResolvedValueOnce(null)
mockRefreshOAuthToken.mockResolvedValueOnce({
ok: false,
errorCode: 'invalid_grant',
message: 'Failed',
})

const token = await refreshAccessTokenIfNeeded('credential-id', 'test-user-id', 'request-id')

Expand Down
Loading
Loading