|
| 1 | +# Sigma Embedding with Databricks OAuth 2.0 (PKCE) |
| 2 | + |
| 3 | +This application demonstrates secure embedding of Sigma Analytics dashboards using **Databricks connection-level OAuth** with **PKCE** (Proof Key for Code Exchange). Users authenticate with their Databricks credentials, and queries run with their individual permissions. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +- **Connection-Level OAuth**: Each user authenticates with their own Databricks credentials |
| 8 | +- **PKCE Security**: Protection against authorization code interception attacks |
| 9 | +- **Automatic Token Refresh**: Seamless token renewal before expiration |
| 10 | +- **Session Management**: Secure server-side session storage |
| 11 | +- **User-Level Permissions**: Queries execute with authenticated user's Databricks permissions |
| 12 | +- **CLI Mode**: Standalone token generation for testing |
| 13 | +- **Web Application Mode**: Full Express.js server with OAuth flow |
| 14 | + |
| 15 | +## Architecture |
| 16 | + |
| 17 | +``` |
| 18 | +┌─────────────┐ ┌──────────────┐ ┌─────────────┐ |
| 19 | +│ Browser │ ◄─────► │ Express App │ ◄─────► │ Databricks │ |
| 20 | +└─────────────┘ └──────────────┘ └─────────────┘ |
| 21 | + │ |
| 22 | + │ Encrypted Token |
| 23 | + ▼ |
| 24 | + ┌──────────────┐ |
| 25 | + │ Sigma │ |
| 26 | + │ Analytics │ |
| 27 | + └──────────────┘ |
| 28 | +``` |
| 29 | + |
| 30 | +### OAuth Flow |
| 31 | + |
| 32 | +1. User initiates login → Generates PKCE code challenge |
| 33 | +2. Redirect to Databricks → User authenticates |
| 34 | +3. Databricks callback → Exchange code + verifier for tokens |
| 35 | +4. Store tokens in session → Encrypt access token |
| 36 | +5. Embed in Sigma JWT → Dashboard loads with user permissions |
| 37 | + |
| 38 | +## Prerequisites |
| 39 | + |
| 40 | +- Node.js 16+ installed |
| 41 | +- Databricks workspace with OAuth configured |
| 42 | +- Sigma organization with embedding enabled |
| 43 | +- Databricks connection in Sigma configured for OAuth |
| 44 | + |
| 45 | +## Installation |
| 46 | + |
| 47 | +1. **Navigate to the project root directory** |
| 48 | + ```bash |
| 49 | + cd embedding_qs_series_2 |
| 50 | + ``` |
| 51 | + |
| 52 | +2. **Install dependencies** (if not already installed) |
| 53 | + ```bash |
| 54 | + npm install |
| 55 | + ``` |
| 56 | + |
| 57 | +3. **Configure centralized `.env` file** |
| 58 | + |
| 59 | + This QuickStart uses the centralized `.env` file at `/embedding_qs_series_2/.env` |
| 60 | + |
| 61 | + Add your Databricks OAuth configuration to the existing `.env` file (see Configuration section below) |
| 62 | + |
| 63 | +## Configuration |
| 64 | + |
| 65 | +This QuickStart uses the **centralized `.env` file** located at `embedding_qs_series_2/.env` (shared with other QuickStarts). |
| 66 | + |
| 67 | +### Databricks OAuth Setup |
| 68 | + |
| 69 | +1. **Navigate to Databricks Admin Console** → Settings → OAuth |
| 70 | + |
| 71 | +2. **Create OAuth Application** |
| 72 | + - Name: `Sigma Embedding` |
| 73 | + - Redirect URI: `http://localhost:3000/auth/databricks/callback` |
| 74 | + - Scopes: `all-apis` and `offline_access` |
| 75 | + |
| 76 | +3. **Copy credentials** to the centralized `.env` file |
| 77 | + |
| 78 | +### Sigma Embedding Setup |
| 79 | + |
| 80 | +1. **Go to Sigma Admin** → Developer Access |
| 81 | + |
| 82 | +2. **Use existing shared embed credentials** (CLIENT_ID and SECRET) |
| 83 | + - These are already configured at the top of the `.env` file |
| 84 | + |
| 85 | +3. **Create Databricks connection** with OAuth enabled |
| 86 | + - Admin → Connections → Your Databricks Connection |
| 87 | + - Enable "Connection-level OAuth" |
| 88 | + - Copy Connection ID from URL |
| 89 | + |
| 90 | +4. **Create a Sigma workbook** using your Databricks connection |
| 91 | + |
| 92 | +### Centralized .env Configuration |
| 93 | + |
| 94 | +Add these variables to the `embedding_qs_series_2/.env` file: |
| 95 | + |
| 96 | +```env |
| 97 | +############################################### |
| 98 | +# Embedding 16: Databricks OAuth (Connection-Level) |
| 99 | +############################################### |
| 100 | +
|
| 101 | +# Sigma Embedding Settings (override defaults if needed) |
| 102 | +DATABRICKS_OAUTH_BASE_URL=https://app.sigmacomputing.com/your-org/workbook/workbook-id |
| 103 | +DATABRICKS_OAUTH_EMAIL= |
| 104 | +DATABRICKS_OAUTH_ACCOUNT_TYPE=View |
| 105 | +DATABRICKS_OAUTH_TEAMS= |
| 106 | +
|
| 107 | +# Databricks OAuth Configuration |
| 108 | +DATABRICKS_HOST=https://adb-1234567890123456.2.azuredatabricks.net |
| 109 | +DATABRICKS_ACCOUNT_ID= |
| 110 | +DATABRICKS_OAUTH_CLIENT_ID=your-oauth-client-id |
| 111 | +DATABRICKS_OAUTH_CLIENT_SECRET=your-oauth-client-secret |
| 112 | +DATABRICKS_REDIRECT_URI=http://localhost:3000/auth/databricks/callback |
| 113 | +DATABRICKS_AUTH_LEVEL=workspace |
| 114 | +
|
| 115 | +# Databricks Connection ID in Sigma |
| 116 | +DATABRICKS_CONNECTION_ID=your-connection-id |
| 117 | +
|
| 118 | +# Session Secret |
| 119 | +DATABRICKS_SESSION_SECRET=change-this-to-random-string-in-production |
| 120 | +
|
| 121 | +# Optional: Save token to file in CLI mode |
| 122 | +DATABRICKS_SAVE_TOKEN_TO_FILE=false |
| 123 | +``` |
| 124 | + |
| 125 | +**Note:** The shared `CLIENT_ID` and `SECRET` at the top of the `.env` file are used for Sigma JWT signing. |
| 126 | + |
| 127 | +## Usage |
| 128 | + |
| 129 | +### Web Application Mode |
| 130 | + |
| 131 | +Start the Express server from the databricks_oauth directory: |
| 132 | + |
| 133 | +```bash |
| 134 | +cd public/databricks_oauth |
| 135 | +npm start |
| 136 | +``` |
| 137 | + |
| 138 | +Visit `http://localhost:3000` and: |
| 139 | +1. Click "Login with Databricks" |
| 140 | +2. Authenticate with your Databricks credentials |
| 141 | +3. View embedded Sigma dashboard with your permissions |
| 142 | + |
| 143 | +### CLI Mode (Standalone Token Generation) |
| 144 | + |
| 145 | +Generate tokens for testing: |
| 146 | + |
| 147 | +```bash |
| 148 | +cd public/databricks_oauth |
| 149 | +npm run token:cli |
| 150 | +``` |
| 151 | + |
| 152 | +This will: |
| 153 | +1. Open browser for Databricks authentication |
| 154 | +2. Generate PKCE challenge and exchange for tokens |
| 155 | +3. Display token information |
| 156 | +4. Optionally save to `databricks_token.json` |
| 157 | + |
| 158 | +**Note:** The CLI mode uses the same centralized `.env` configuration as the web application. |
| 159 | + |
| 160 | +## File Structure |
| 161 | + |
| 162 | +``` |
| 163 | +databricks_oauth/ |
| 164 | +├── server.js # Express server with OAuth routes |
| 165 | +├── databricks-token-cli.js # Standalone CLI token generator |
| 166 | +├── package.json # Dependencies and scripts |
| 167 | +├── .env.example # Environment template |
| 168 | +├── helpers/ |
| 169 | +│ ├── pkce.js # PKCE utilities (RFC 7636) |
| 170 | +│ ├── databricks-auth.js # Databricks OAuth functions |
| 171 | +│ └── embed-api-oauth.js # Sigma JWT signing with encrypted tokens |
| 172 | +├── index.html # Dashboard page (authenticated) |
| 173 | +└── login.html # Login page |
| 174 | +``` |
| 175 | + |
| 176 | +## Key Components |
| 177 | + |
| 178 | +### PKCE Implementation (`helpers/pkce.js`) |
| 179 | + |
| 180 | +Generates cryptographically secure code verifiers and SHA-256 challenges per RFC 7636. |
| 181 | + |
| 182 | +### Databricks Auth (`helpers/databricks-auth.js`) |
| 183 | + |
| 184 | +- `getAuthorizationUrl()`: Builds OAuth authorization URL |
| 185 | +- `exchangeCodeForToken()`: Exchanges auth code for access/refresh tokens |
| 186 | +- `refreshAccessToken()`: Refreshes expired tokens |
| 187 | +- `getCurrentUser()`: Fetches user info from Databricks SCIM API |
| 188 | + |
| 189 | +### Sigma Embedding (`helpers/embed-api-oauth.js`) |
| 190 | + |
| 191 | +- `encryptToken()`: AES-256 encryption of Databricks access token |
| 192 | +- `generateSignedUrl()`: Creates signed Sigma embed URL with encrypted OAuth token in JWT |
| 193 | + |
| 194 | +### Server Routes (`server.js`) |
| 195 | + |
| 196 | +| Route | Description | |
| 197 | +|-------|-------------| |
| 198 | +| `GET /` | Redirects to login | |
| 199 | +| `GET /auth/databricks/login` | Initiates OAuth flow | |
| 200 | +| `GET /auth/databricks/callback` | Handles OAuth callback | |
| 201 | +| `GET /dashboard` | Dashboard page (requires auth) | |
| 202 | +| `GET /api/embed-url` | Returns signed Sigma embed URL | |
| 203 | +| `GET /logout` | Destroys session | |
| 204 | +| `GET /health` | Health check | |
| 205 | + |
| 206 | +## Security Features |
| 207 | + |
| 208 | +- **PKCE**: Protects against code interception |
| 209 | +- **State Parameter**: CSRF protection |
| 210 | +- **Session Storage**: Server-side token storage (not exposed to client) |
| 211 | +- **Token Encryption**: AES-256-CBC encryption for Databricks tokens |
| 212 | +- **HTTPS Ready**: Configurable for production with HTTPS |
| 213 | +- **Auto-Refresh**: Tokens refreshed 5 minutes before expiry |
| 214 | + |
| 215 | +## Troubleshooting |
| 216 | + |
| 217 | +### "Missing required environment variables" |
| 218 | + |
| 219 | +Ensure `.env` file exists and contains all required variables from `.env.example`. |
| 220 | + |
| 221 | +### "State mismatch - possible CSRF attack" |
| 222 | + |
| 223 | +Clear browser cookies and restart the server. This usually happens during development when sessions are lost. |
| 224 | + |
| 225 | +### "Token exchange failed" |
| 226 | + |
| 227 | +Verify: |
| 228 | +- Databricks OAuth client ID and secret are correct |
| 229 | +- Redirect URI matches Databricks OAuth app configuration exactly |
| 230 | +- `DATABRICKS_HOST` is correct |
| 231 | + |
| 232 | +### "Failed to generate embed URL" |
| 233 | + |
| 234 | +Check: |
| 235 | +- `SIGMA_BASE_URL` points to a valid workbook |
| 236 | +- `SIGMA_CONNECTION_ID` is correct (from connection URL in Sigma Admin) |
| 237 | +- Sigma connection has OAuth enabled |
| 238 | + |
| 239 | +### Embed shows "No data" or permission errors |
| 240 | + |
| 241 | +Verify: |
| 242 | +- Authenticated Databricks user has permissions to query the data |
| 243 | +- Sigma workbook uses the correct Databricks connection |
| 244 | +- Connection-level OAuth is enabled in Sigma connection settings |
| 245 | + |
| 246 | +## Production Deployment |
| 247 | + |
| 248 | +For production use: |
| 249 | + |
| 250 | +1. **Enable HTTPS**: Set `cookie.secure = true` in `server.js` |
| 251 | +2. **Change SESSION_SECRET**: Use a strong random string |
| 252 | +3. **Update Redirect URI**: Add production URL to Databricks OAuth app |
| 253 | +4. **Environment Variables**: Use secure secret management (not `.env` files) |
| 254 | +5. **Rate Limiting**: Add rate limiting middleware |
| 255 | +6. **Logging**: Implement production logging (e.g., Winston) |
| 256 | +7. **Error Handling**: Add comprehensive error handling and monitoring |
| 257 | + |
| 258 | +## Additional Resources |
| 259 | + |
| 260 | +- [Sigma Embedding Documentation](https://help.sigmacomputing.com/docs/embedding) |
| 261 | +- [Databricks OAuth Documentation](https://docs.databricks.com/dev-tools/auth.html#oauth-2-0) |
| 262 | +- [OAuth 2.0 with PKCE (RFC 7636)](https://datatracker.ietf.org/doc/html/rfc7636) |
| 263 | +- [Sigma QuickStarts](https://quickstarts.sigmacomputing.com/) |
| 264 | + |
| 265 | +## License |
| 266 | + |
| 267 | +MIT |
0 commit comments