Conversational AI

Authentication done right: API keys, OIDC, and the end of Basic Auth

Part 9 of 12 – Conversation Intelligence Platform series Back to Part 1

Authentication is one of those things where the gap between “works” and “done right” is enormous and mostly invisible until something goes wrong. This post is about what “done right” looks like for a platform serving developers, the browser portal, and native apps simultaneously – and what’s changing for existing customers. Quick note on availability: the new platform and Conversation Intelligence API are currently in beta, available to customers enrolled in the carrier services beta programme. API keys are live now. Portal login via OIDC is the next stage.

The platform is designed around three authentication mechanisms. All three are resolved at the edge, by the authentication layer described in Part 8, before a request reaches any service. Downstream services have no idea which mechanism was used.

Bearer API keys are for machine integrations – server-to-server calls, automation, CI pipelines. Keys carry scopes at issuance; a key issued with intelligence:read can read Intelligence API resources and nothing else. Keys are stored hashed – the plaintext key is shown once at issuance and never again. Revocation is effective immediately for practical purposes.

This is what’s live now.

Bearer JWTs are for the portal and native apps. The portal uses OAuth 2.0 Authorization Code flow with PKCE – that’s Proof Key for Code Exchange, not passkeys (a different and newer standard). PKCE is an OAuth 2.0 extension that prevents authorization code interception: rather than relying solely on a client secret, it adds a cryptographic challenge-and-verifier pair generated fresh on each login attempt, so intercepting the authorization code alone isn’t enough to get tokens. The access token lives in memory and the refresh token lives in an httpOnly cookie. This is current best practice for browser-based apps: it prevents XSS token theft while keeping session management clean. Native apps use the same OIDC flow but store tokens in the device secure enclave (Keychain on iOS, Keystore on Android), with credentials entered in the system browser rather than the app itself.

This is the next stage – rolling out shortly after launch.

Basic Auth is not a platform authentication mechanism and is not available on any new service endpoint. Existing v3 Wholesale API credentials continue to work for their published deprecation window and no longer.

A service should never need to care how a request was authenticated. Its job is to enforce scope and execute business logic, not understand credential formats. The gateway enforces that separation.

Scopes follow the pattern resource:action. Examples:

intelligence:read   intelligence:write
reporting:read      account:admin

Scopes are stored on the key record at issuance and included in the claims on every validated request. Services check scopes before executing any operation. A request attempting a write without the appropriate write scope gets a 403 with a clear error indicating the missing scope.

The scope taxonomy is defined per-service, with each service introducing its own scope root when it’s added to the platform. Account-level scopes are the baseline every account receives; all other service scopes are product-gated. This is how the platform ensures that a Conversation Intelligence API key can’t accidentally – or deliberately – access Billing data.

The portal migration will affect existing users when it rolls out. Login moves off our own custom flow to a standards-based identity service at auth.simwood.com, which handles the login UI, credential validation, and token issuance with Simwood branding. Existing portal users will be brought across as part of the migration, and we’ll communicate directly with all of them ahead of it. Once cutover, the old login flow is gone and the new service is the only entry point.

For developers building against the platform: if you’re currently using Basic Auth against v3, your deprecation window is a minimum of 12 months from the deprecation notice. Your existing integrations continue working throughout it. Move to an API key before it closes. New integrations against new services use API keys from day one. That’s a feature, not a limitation.

Previous: Part 8 – A new API architecture

Next: Part 10 – Deprecation as a feature

Back to series index

← All posts