Skip to main content
RapidDev - Software Development Agency
bubble-integrationsBubble API Connector

Okta

Connect Bubble to Okta using the API Connector with a Private SSWS token to query the Okta Admin API — search users, deactivate accounts, manage groups, and build audit dashboards from a Repeating Group. For employee SSO login, add an optional Backend Workflow (paid plan required) to handle the OIDC authorization-code exchange server-side.

What you'll learn

  • How to generate an Okta SSWS API token and mark it Private in Bubble's API Connector
  • How to build a user-search Data call with GET /users and avoid the empty-array initialize trap
  • How to add lifecycle Action calls (deactivate, activate, unlock) that operate on Okta user IDs
  • How to query the Okta System Log (GET /logs) and cache results to stay within rate limits
  • How to wire up OIDC SSO login using a Backend Workflow endpoint (paid plan)
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate16 min read2–3 hoursAuth & IdentityLast updated July 2026RapidDev Engineering Team
TL;DR

Connect Bubble to Okta using the API Connector with a Private SSWS token to query the Okta Admin API — search users, deactivate accounts, manage groups, and build audit dashboards from a Repeating Group. For employee SSO login, add an optional Backend Workflow (paid plan required) to handle the OIDC authorization-code exchange server-side.

Quick facts about this guide
FactValue
ToolOkta
CategoryAuth & Identity
MethodBubble API Connector
DifficultyIntermediate
Time required2–3 hours
Last updatedJuly 2026

Two ways to use Okta in Bubble

Okta serves two very different use-cases in Bubble apps. The first — and the one covered in detail here — is the IT admin panel: your Bubble app calls the Okta Admin API with an SSWS static token to search employees, deactivate departing staff, unlock locked accounts, manage group memberships, and display a live System Log audit dashboard. This is entirely achievable with the free-plan-friendly API Connector.

The second use-case is employee SSO login: redirect your Bubble app's users to Okta's OIDC authorization endpoint, then handle the code callback in a Backend Workflow that exchanges the code for tokens server-side. Because Backend Workflows expose a public API endpoint, they are only available on Bubble's Starter plan ($32/mo) and above.

The SSWS token is the key security detail. Okta's SSWS tokens inherit the full permissions of the admin account that created them and never expire on their own (they only expire after 30 days of inactivity or manual revocation). Marking the token value as 'Private' in the API Connector header ensures it is never transmitted to the browser — even in Bubble's visual editor. Always create a dedicated Okta service account with the minimum required admin role rather than using your personal admin credentials.

Integration method

Bubble API Connector

REST calls to https://YOUR_DOMAIN.okta.com/api/v1 with a Private SSWS token in the Authorization header, proxied server-side through Bubble's infrastructure.

Prerequisites

  • An Okta org with admin access — Okta Workforce Identity requires an enterprise contract (no public self-serve free tier for the Admin API)
  • A dedicated Okta service account with a scoped admin role (User Administrator or Read-Only Administrator depending on your use-case)
  • An SSWS API token generated under Security → API → Tokens in the Okta Admin Console
  • A Bubble app on any plan for the Admin API use-case; Starter plan ($32/mo) or above for Backend Workflow SSO
  • Basic familiarity with the Bubble Plugins tab and Workflow editor

Step-by-step guide

1

Create a dedicated Okta service account and generate an SSWS token

Log into your Okta Admin Console at yourorg.okta.com/admin. Navigate to Directory → People and create a new user — name it something like 'bubble-integration-service' so it is clearly identifiable in audit logs. Assign this service account the minimum admin role your use-case requires: 'Read-Only Administrator' is sufficient for search and audit log queries; 'User Administrator' is needed for deactivation, activation, and group management; 'Super Administrator' should be avoided. Once the service account exists, sign into Okta as that service account (or have your Okta admin do this step). Navigate to Security → API → Tokens and click 'Create Token'. Give it a descriptive name like 'Bubble Admin Panel'. Copy the token value immediately — Okta shows it only once. Store it temporarily in a secure note (password manager) because you'll paste it into Bubble in the next step. Note the token expiry behavior: SSWS tokens do not expire on a fixed schedule, but they do expire after 30 days of inactivity. Set a calendar reminder to make an API call through your Bubble app at least once a month, or plan a manual token rotation. An expired token returns 401 on every Admin API call with no other error message, so it's easy to mistake for a broken integration.

Pro tip: Create a shared Okta admin account specifically for integrations rather than using a personal admin's token. If the personal admin leaves the company and their account is deactivated, all their tokens are revoked immediately — breaking your Bubble integration.

Expected result: You have an SSWS token value copied and ready. The token appears in Security → API → Tokens with a green 'Active' status.

2

Add the Okta API Connector in Bubble with a Private SSWS header

Open your Bubble app in the editor. Click the Plugins tab in the left sidebar and then click 'Add plugins'. In the search box type 'API Connector' and install the plugin named 'API Connector' by Bubble (it is free and maintained by Bubble itself). After installation, click 'API Connector' in the Plugins tab to open its configuration panel. Click 'Add another API' and name it 'Okta'. In the 'Shared headers for all calls' section, add a new header: - Key: Authorization - Value: SSWS YOUR_TOKEN_VALUE (replace with your actual token — the exact format is 'SSWS ' followed by the token, all in one string) IMPORTANT: Click the checkbox to the right of the Authorization header value to mark it as 'Private'. This checkbox prevents the token from ever being sent to the browser. Without this checkbox, the token is visible in browser developer tools network requests. CORS is not an issue because Bubble's API Connector runs on Bubble's servers, not in the browser. Set the Base URL to: https://YOUR_DOMAIN.okta.com/api/v1 (replace YOUR_DOMAIN with your actual Okta organization domain, e.g., company.okta.com).

okta_api_connector_config.json
1{
2 "api_name": "Okta",
3 "base_url": "https://YOUR_DOMAIN.okta.com/api/v1",
4 "shared_headers": [
5 {
6 "key": "Authorization",
7 "value": "SSWS <private>",
8 "private": true
9 }
10 ]
11}

Pro tip: The Authorization header format is 'SSWS {token}' — uppercase SSWS, a space, then the token. Using 'Bearer' instead of 'SSWS' returns 401 immediately. This is the most common setup mistake for Okta.

Expected result: The Okta API group appears in your API Connector with the Authorization header showing the Private lock icon. No calls have been initialized yet.

3

Initialize the user-search Data call and add lifecycle Action calls

Still in the Okta API Connector, click 'Add another call' under the Okta group. Configure the user search call: - Name: Search Users - Method: GET - URL: https://YOUR_DOMAIN.okta.com/api/v1/users - Set 'Use as': Data - Add parameter: q (type: text, initial value: a) - Add parameter: limit (type: number, initial value: 1) Click 'Initialize call'. Bubble sends a real request to Okta and reads the response shape. This step is mandatory — Bubble cannot map fields to UI elements without a successful response with real data. If Okta returns a 200 but with an empty array (no users matching the query), Bubble's initializer rejects it. Using q=a and limit=1 ensures the first-letter search will almost always find at least one user, avoiding this empty-array trap. After initialization succeeds, you'll see Okta's user fields auto-detected: id, status, profile.firstName, profile.lastName, profile.email, profile.login. Click 'Save' to confirm the field mapping. Now add a second call for deactivating a user: - Name: Deactivate User - Method: POST - URL: https://YOUR_DOMAIN.okta.com/api/v1/users/[id]/lifecycle/deactivate (where [id] is a dynamic path param) - Set 'Use as': Action (not Data — this call has no response body) - Add path parameter: id (text) Repeat to add similar Action calls for 'Activate User' (/lifecycle/activate), 'Unlock User' (/lifecycle/unlock), and 'Expire Password' (/lifecycle/expirePassword) following the same pattern. These all use POST with no body and the user's Okta ID as the path segment.

okta_calls_config.json
1{
2 "call_name": "Search Users",
3 "method": "GET",
4 "url": "https://YOUR_DOMAIN.okta.com/api/v1/users",
5 "use_as": "Data",
6 "params": [
7 { "key": "q", "value": "<dynamic>", "initial": "a" },
8 { "key": "limit", "value": "<dynamic>", "initial": "25" }
9 ]
10}
11
12{
13 "call_name": "Deactivate User",
14 "method": "POST",
15 "url": "https://YOUR_DOMAIN.okta.com/api/v1/users/<dynamic_id>/lifecycle/deactivate",
16 "use_as": "Action"
17}

Pro tip: Okta user IDs are internal opaque identifiers in the format '00u1a2b3c4d5e6f7g8' — not email addresses. Lifecycle action calls (deactivate, activate, unlock) 404 if you pass an email address as the path segment. Always use the 'id' field from the Search Users response, not 'profile.email'.

Expected result: The 'Search Users' call is initialized and shows detected fields including id, status, profile.firstName, profile.lastName, profile.email. Action calls for Deactivate User and others are saved. No runtime errors.

4

Build the user search UI and wire up lifecycle workflows

Switch to the Design editor in Bubble. Add a search input element to your page. Add a Repeating Group below it — set its Data source to 'Get data from an external API' → 'Okta - Search Users' and map the q parameter to the search input's value. This creates a live-search user directory. Inside the Repeating Group's cell, add text elements for the user's name and status: bind them to Current cell's Okta Search Users's profile.firstName, profile.lastName, profile.email, and status. Add a Status badge that changes color based on the status value (ACTIVE = green, DEPROVISIONED = red, LOCKED_OUT = orange) using Bubble's conditional formatting. Add a 'Deactivate' button inside the Repeating Group cell. Create a workflow on that button's click event: 1. Show a confirmation popup (Alert or custom popup with the user's name) 2. On confirmation: run API Connector action 'Okta - Deactivate User' with id = Current cell's Okta Search Users's id 3. After the action: refresh the Repeating Group's data source to reflect the updated status 4. Show a success notification text element Set up Privacy rules on your Bubble database: if your Bubble app also stores user records, go to Data tab → Privacy and add rules restricting who can read/write those records. Any Thing that stores Okta user data pulled via API should have privacy rules preventing public read access. For the System Log (audit) dashboard: add a separate page with a Repeating Group bound to 'Okta - Get Logs' (GET /logs). Use Bubble's 'Schedule API workflow' in a Workflow to cache results every 60 seconds — the /logs endpoint is rate-limited to 60 req/min. Without caching, refreshing the dashboard rapidly will trigger 429 errors.

Pro tip: The System Log endpoint (GET /api/v1/logs) rate limit is 60 req/min — much lower than the /users endpoint (600 req/min). Use a Bubble custom state to store the last fetch timestamp and skip the API call if less than 60 seconds have elapsed since the last fetch.

Expected result: The user search Repeating Group displays Okta users filtered by the search input. Clicking 'Deactivate' prompts a confirmation and then updates the user's status in Okta, with the Repeating Group refreshing to show 'DEPROVISIONED'.

5

(Optional) Add OIDC SSO login via a Backend Workflow

This step requires a paid Bubble plan (Starter $32/mo or above) because it uses Backend Workflows, which expose public API endpoints. The Free plan cannot use Backend Workflows. Navigate to Settings → API in your Bubble app editor. Enable 'This app exposes a Workflow API'. Then go to the Backend Workflows section and create a new API Workflow named 'okta_callback'. Enable 'This workflow can be run without authentication' for the callback endpoint. Note the endpoint URL: https://yourapp.bubbleapps.io/api/1.1/wf/okta_callback In your Okta Admin Console, create a new OIDC Web Application (not SPA): set the Sign-in redirect URI to your Backend Workflow URL. Save the Client ID and Client Secret. Back in Bubble, add a second API Connector group named 'Okta OAuth'. Add a call: - Name: Exchange Code for Token - Method: POST - URL: https://YOUR_DOMAIN.okta.com/oauth2/v1/token - Body type: form-url-encoded - Body params: grant_type=authorization_code, code={{code}} (dynamic), redirect_uri={{redirect_uri}}, client_id={{client_id}}, client_secret={{client_secret}} - Mark client_secret as Private In your okta_callback Backend Workflow: add 'Detect request data' to capture the 'code' query param. Add an action to run the 'Exchange Code for Token' API call passing the detected code. Store the returned id_token or user info in your Bubble User record for session management. For the login button on your Bubble frontend: use a 'Go to external website' workflow action pointing to: https://YOUR_DOMAIN.okta.com/oauth2/v1/authorize?client_id={CLIENT_ID}&response_type=code&scope=openid profile email&redirect_uri={YOUR_WORKFLOW_URL}&state={random_value}

okta_oidc_config.json
1{
2 "call_name": "Exchange Code for Token",
3 "method": "POST",
4 "url": "https://YOUR_DOMAIN.okta.com/oauth2/v1/token",
5 "body_type": "form-url-encoded",
6 "body_params": [
7 { "key": "grant_type", "value": "authorization_code" },
8 { "key": "code", "value": "<dynamic>" },
9 { "key": "redirect_uri", "value": "<dynamic>" },
10 { "key": "client_id", "value": "<dynamic>" },
11 { "key": "client_secret", "value": "<private>" }
12 ]
13}
14
15Okta Authorization URL:
16https://YOUR_DOMAIN.okta.com/oauth2/v1/authorize
17 ?client_id={CLIENT_ID}
18 &response_type=code
19 &scope=openid%20profile%20email
20 &redirect_uri={YOUR_BACKEND_WORKFLOW_URL}
21 &state={RANDOM_STATE_VALUE}

Pro tip: If you need help configuring the OIDC Backend Workflow or wiring up multi-step auth flows for enterprise Okta deployments, RapidDev's team has built hundreds of Bubble apps with integrations like this — free scoping call at rapidevelopers.com/contact.

Expected result: Clicking the 'Sign in with Okta' button redirects users to the Okta login page. After authentication, Okta redirects back to your Backend Workflow URL with a code param. The workflow exchanges the code for tokens and stores user info in your Bubble database.

Common use cases

Employee offboarding dashboard

HR managers open a Bubble page, search for a departing employee by name or email, and click 'Deactivate' — Bubble calls POST /users/{id}/lifecycle/deactivate through the API Connector. The employee's Okta account is suspended immediately, cutting access to all SSO-connected apps at once without IT involvement.

Bubble Prompt

Build an employee offboarding page in Bubble. Show a search input that queries GET /users?q={{input}}&limit=25 from the Okta API Connector and displays results in a Repeating Group. Add a 'Deactivate' button that runs POST /users/{id}/lifecycle/deactivate and shows a success alert.

Copy this prompt to try it in Bubble

Audit log dashboard for compliance

Security teams need a live view of Okta System Log events — failed logins, policy changes, MFA bypasses — inside a Bubble internal tool. Pull GET /logs with SCIM filter parameters and display events in a searchable, date-filtered Repeating Group. Cache results for 60 seconds to avoid hitting the 60 req/min rate limit on the logs endpoint.

Bubble Prompt

Create an audit log page in Bubble that calls GET /logs from Okta with a 'since' datetime param and displays events in a Repeating Group sorted by published date. Add a date-range filter. Cache the last result in a custom state and only re-fetch when the user changes the filter.

Copy this prompt to try it in Bubble

Group membership manager

IT admins add or remove employees from Okta groups directly from a Bubble app — useful for managing access to shared SaaS tools. Use GET /groups to list groups, GET /groups/{id}/users to show members, and PUT /groups/{id}/users/{userId} or DELETE /groups/{id}/users/{userId} to modify membership.

Bubble Prompt

Build a group membership manager in Bubble. Show a dropdown of Okta groups from GET /groups. When a group is selected, display its current members from GET /groups/{id}/users in a Repeating Group. Add 'Add user' and 'Remove' buttons that call the appropriate PUT/DELETE endpoints.

Copy this prompt to try it in Bubble

Troubleshooting

All API calls return 401 Unauthorized

Cause: The SSWS token is either using the wrong format in the Authorization header, or the token has expired due to 30 days of inactivity.

Solution: Check that the Authorization header value is exactly 'SSWS YOUR_TOKEN' — uppercase SSWS, a single space, then the token. 'Bearer' or lowercase 'ssws' both cause 401. If the format is correct, go to Security → API → Tokens in the Okta Admin Console and verify the token shows 'Active' status. If expired, create a new token, update the API Connector header, and re-initialize all calls.

Lifecycle action calls (deactivate, activate) return 404 Not Found

Cause: The user ID passed as the path segment is an email address instead of Okta's internal user ID.

Solution: Okta's lifecycle endpoints require the internal user ID (format: 00u1a2b3c4d5e6f7g8), not the user's email or login. In your Repeating Group workflow, use Current cell's Okta Search Users's id — not profile.email or profile.login. These fields look similar in the Bubble UI but the id field is the opaque Okta identifier.

Initialize call fails with 'There was an issue setting up your call' — empty array response

Cause: Bubble's API Connector requires a real non-empty response to detect field shapes. If your GET /users request returns an empty array (no users match the query), initialization fails even though the HTTP status is 200.

Solution: Use q=a&limit=1 as the initialization parameters. A single-letter search will almost always return at least one user from any Okta org. After initialization succeeds with real user data, you can change the dynamic parameters in your actual Bubble workflows to whatever search term the user enters.

System Log dashboard triggers 429 Too Many Requests after a few refreshes

Cause: The Okta GET /logs endpoint is rate-limited to 60 requests per minute — much lower than the /users endpoint. Manually refreshing the page or having multiple users view the dashboard simultaneously exhausts this limit quickly.

Solution: Add a custom state on your page (type: date) to store the last fetch timestamp. At the start of the 'Refresh logs' workflow, add a condition: only proceed if current datetime minus last_fetch timestamp is more than 60 seconds. Store the current datetime in the custom state after each successful fetch. This effectively rate-limits your dashboard refreshes to match Okta's limit.

Backend Workflow SSO callback URL gives 'Workflow API is not enabled' error

Cause: The Backend Workflow API endpoint is only available on paid Bubble plans. Free plan apps cannot expose Backend Workflow URLs.

Solution: Upgrade your Bubble app to Starter ($32/mo) or above. Then go to Settings → API and enable 'This app exposes a Workflow API'. The Backend Workflow endpoint URL (https://yourapp.bubbleapps.io/api/1.1/wf/workflow_name) will only be reachable after enabling this setting on a paid plan.

Best practices

  • Always create a dedicated Okta service account for the Bubble integration — use a functional email like bubble-integration@yourcompany.com, not a personal admin's account. If the personal admin leaves, their account deactivation revokes all their SSWS tokens immediately.
  • Apply least-privilege admin roles: 'Read-Only Administrator' for dashboards and audit tools; 'User Administrator' for lifecycle management. Avoid 'Super Administrator' scope for integration tokens.
  • Mark the SSWS token value as 'Private' in the API Connector shared header — this is the single most important security step. Private headers are never transmitted to the browser regardless of how Bubble renders the page.
  • Set a calendar reminder for SSWS token rotation. Tokens expire after 30 days of inactivity and expire silently — the only symptom is a sudden wave of 401 errors across all Admin API calls with no other error message.
  • Use Bubble's Privacy rules (Data tab → Privacy) on any Thing that stores Okta user data pulled via the API. Without privacy rules, Bubble data can be read by anyone who knows the right API endpoint pattern.
  • Cache System Log results in a custom state and throttle refreshes to once per 60 seconds. The /logs endpoint has a 60 req/min rate limit — far lower than the /users endpoint — and dashboard-heavy pages can exhaust it in seconds.
  • For the OIDC SSO path, generate a random 'state' parameter on each authorization URL and verify it in the callback Backend Workflow to prevent CSRF attacks. Bubble's 'Generate a random string' action can create this value.
  • Monitor Workload Unit (WU) consumption in Bubble's Logs tab. Each API Connector call, Backend Workflow run, and database operation counts toward your WU budget. A polling-heavy dashboard can consume significant WUs — prefer event-driven refreshes triggered by user action over automatic polling.

Alternatives

Frequently asked questions

Does Bubble support Okta SSO for logging into the Bubble app itself?

Not natively. Bubble's built-in authentication doesn't support external SSO providers. You can implement a custom OIDC flow where users click 'Sign in with Okta', are redirected to Okta's authorization page, and return to a Backend Workflow that stores their session data in a Bubble User record. This requires a paid Bubble plan for Backend Workflows. An alternative is to keep Bubble's native authentication and use the Okta Admin API only for IT management tasks.

My Okta authorization token format is 'Bearer' but all examples show 'SSWS' — what's the difference?

Okta uses two completely different token types. SSWS (Secure Web Services Security) tokens are static admin tokens generated in the Okta Admin Console under Security → API → Tokens — these use 'SSWS {token}' in the Authorization header. OAuth2 Bearer tokens are short-lived access tokens issued during OIDC flows — these use 'Bearer {access_token}'. The API Connector setup described here uses the SSWS token for the Admin API. If you're implementing OIDC SSO, the code-exchange call returns a separate Bearer token used for accessing user profile information.

Can I use this integration to sync all Okta users into a Bubble database table?

Yes, but plan for pagination. GET /users returns up to 200 users per page (set with limit param) and uses cursor-based pagination via the Link header in Okta's response. Bubble doesn't natively parse Link headers, so the practical approach is to use $skip/$top style offset pagination with multiple sequential API calls in a Backend Workflow, building up a list of users across pages. This is a paid-plan workflow and consumes Workload Units for each call.

Is there a rate limit I should worry about for the user search?

The GET /users endpoint allows 600 requests per minute — generous enough for most Bubble dashboards. The GET /logs endpoint for System Log queries is limited to 60 requests per minute. Build caching logic (using a Bubble custom state for last-fetch timestamp) for any dashboard that displays log data, especially if multiple users might view it simultaneously.

What happens to existing Okta SSWS tokens when the admin account that created them is deactivated?

All SSWS tokens created by a deactivated Okta account are immediately revoked. Your Bubble integration will start returning 401 on every Admin API call with no warning. This is why creating a dedicated service account for the integration (separate from any individual's admin account) is essential — the service account token remains valid as long as the service account stays active.

Do I need Okta's Workforce Identity or Customer Identity product for this integration?

The Admin API use-case (user search, deactivation, group management, System Log) requires Okta Workforce Identity, which is an enterprise contract product with no public self-serve free tier. The OIDC SSO consumer login path uses Okta's authorization server, which is part of Workforce Identity. If you're looking for a consumer-facing identity platform with a free tier, consider Auth0 (now owned by Okta) which has a free tier supporting up to 7,500 monthly active users.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Integrations are where projects stall

We wire Bubble integrations like this one every week — auth, webhooks, edge cases included. Fixed-price builds from $13K, delivered in 6–10 weeks.

Talk to an integration engineer

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.