Product documentation
Updated September 27, 2026

OAuth 2.0 Sign-In: Browser and Device Code

Many APIs sit behind an identity provider such as Microsoft Entra ID, Okta, Auth0, Keycloak or Google, and only accept a token issued to a signed-in user. You cannot get that token with a client ID and secret alone.

View as Markdown

Applies to: All editions · Web app and Desktop app · Access to the project's settings

Overview

Many APIs sit behind an identity provider such as Microsoft Entra ID, Okta, Auth0, Keycloak or Google, and only accept a token issued to a signed-in user. You cannot get that token with a client ID and secret alone. A person has to sign in, often with multi-factor authentication (MFA).

Shift-Left Studio lets you sign in to an OAuth 2.0 authentication profile once, in your own browser or with a short code. After that, Studio keeps the sign-in alive: it refreshes the access token before it expires, so every test run, pack, schedule and CI run gets a valid token without anyone signing in again.

This article covers the two interactive flows, Authorization Code (sign in with browser) and Device Code (sign in with a code). For the other OAuth 2.0 flows and every other method, see Authentication Profiles: Choose and Configure a Method.

Key concepts

TermMeaning
Authorization Code with PKCEThe standard way to sign in as a user. Studio opens the provider's sign-in page; the provider sends a one-time code back to Studio, which exchanges it for tokens. PKCE protects that exchange, so a public client needs no client secret.
Device CodeYou see a short code in Studio and type it at the provider's page on any device. No redirect is involved.
Redirect URIThe address the provider sends you back to after sign-in. There is exactly one per installation, and Studio shows it to you.
Access tokenThe short-lived token sent as Authorization: Bearer … on each request.
Refresh tokenA longer-lived token Studio uses to get new access tokens. Requires the offline_access scope with most providers.
GrantThe result of a sign-in: who signed in, the tokens, and when they expire.

Which flow should I use?

FlowUse it whenNeeds a person?Renews itself?
Authorization Code (sign in with browser)You test as a user. The standard choice. MFA and passkeys work.OnceYes
Device Code (sign in with a code)The browser cannot reach Studio's sign-in callback (a proxy, a locked-down desktop, a remote server).OnceYes
Client Credentials (app only, no user)The API accepts an application identity, with no user.NeverYes (fetches a new token)
Password Grant (username + password)Legacy first-party APIs only. Microsoft Entra ID refuses it for accounts with MFA or Conditional Access.NeverYes (fetches a new token)
Implicit (legacy — paste a token)Avoid. It cannot fetch a token; a pasted token expires.—No

Before you begin

  • Register an application with your identity provider and note its Client ID. For a browser sign-in, a public client (for example, Entra's "Mobile and desktop applications" platform) needs no client secret.
  • Know the scopes the API needs. Include offline_access so the provider issues a refresh token.
  • Use a dedicated test account. Every run that uses this profile acts as the person who signed in.
  • On a server installation, an administrator must have set the server's public address for browser sign-in (see For administrators). Device Code works without it.

Step 1 — Create the OAuth 2.0 profile

  1. Go to Project Settings → Authentication Profiles and click New Profile.
  2. Enter a Profile Name and click Next.
  3. Under Authentication Method, select OAuth 2.0.
  4. In OAuth Flow, choose Authorization Code (sign in with browser) or Device Code (sign in with a code). A short guide under the selector explains the flow you picked.

Step 2 — Fill in the provider's details

The quickest way is a provider preset:

  1. In Fill in for a provider (optional), choose Microsoft Entra ID (Azure AD), Okta, Auth0, Keycloak or Google.
  2. Fill in the boxes that appear, for example Tenant (ID or domain) and API scope for Entra, Okta domain and Authorization server for Okta, Auth0 domain and API audience for Auth0, or Keycloak URL and Realm for Keycloak.
  3. Click Fill in. Studio fills the Authorization URL, Token URL, Device Authorization URL, Scopes, and, where the provider has one, the Token Revocation URL. Every field stays editable.

Then complete the rest:

  1. Enter the Client ID.
  2. Leave Client Secret blank for a public (PKCE) client. Enter it only if your app registration is a confidential client. It is stored encrypted.
  3. Check Scopes. For a user sign-in they usually look like openid profile offline_access api://<app-id>/.default.
  4. Set Client Authentication. Most providers accept Send as Basic Auth header. Microsoft Entra ID expects Send as request body (the preset sets this).
ProviderWhat the preset adds
Microsoft Entra IDv2.0 endpoints for your tenant, openid profile offline_access plus your API scope, request-body client authentication, and prompt=select_account.
OktaEndpoints for your authorization server, revocation URL, openid profile offline_access.
Auth0Endpoints, revocation URL, and your API audience on both sign-in and token requests. Without an audience, Auth0 issues a token no API accepts.
KeycloakOpenID Connect endpoints for your realm, revocation URL.
GoogleGoogle's endpoints, and access_type=offline with prompt=consent so a refresh token is returned.

Step 3 — Register the redirect URI (browser sign-in only)

In the Browser sign-in panel, Studio shows Register this redirect URI with your provider: followed by the address. Click Copy and add it to your app registration. You do this once per installation.

InstallationRedirect URI looks likeRegister it as (Entra)
Desktop apphttp://localhost:<port>/api/oauth/callbackMobile and desktop applications (any localhost port matches)
Cloud or server installationhttps://<your Studio address>/api/oauth/callbackWeb (exact match)

Important: Use the address Studio shows, not a callback URL from another tool such as Postman. A redirect URI that does not match what is registered is the most common reason a provider rejects the sign-in.

If the panel instead says that browser sign-in needs the server's public address, the server has not been configured for it yet. Use Device Code until an administrator sets it.

Step 4 — Sign in

Browser sign-in (Authorization Code)

  1. Click Sign in with browser. Studio saves the profile first, then opens the provider's sign-in page in your system browser. In the Desktop app this is your default browser, so your existing session, MFA and passkeys work.
  2. Sign in at the provider. The panel shows Waiting for you to finish signing in in your browser… If the page did not open, click Open the sign-in page again.
  3. When the browser shows Signed in, close it and return to Studio. The panel now reads, for example, Signed in as jane@contoso.com · access token valid for 59 min · refreshes automatically.

Device sign-in (Device Code)

  1. Click Sign in with a code.
  2. The panel shows Open the page below on any device and enter this code:, a code such as ABCD-EFGH, and a link.
  3. Open the link on any device, type the code, and sign in.
  4. The panel updates to Signed in on its own.

A sign-in that is not finished within 10 minutes expires. Click Cancel to stop waiting, then start again.

  1. Click through to Save Profile, then Activate the profile for its environment if it is not already active.

What happens on a run

  • The server holds the sign-in. The refresh token is stored encrypted on the server, and only the server uses it. Providers such as Entra and Okta issue a new refresh token each time one is used (refresh-token rotation); if two parties refreshed the same sign-in, they would invalidate each other.
  • Tokens are cached. An access token is reused until it is about to expire, so a pack makes one token call, not one per test. When it is close to expiry, the server refreshes it and stores the new refresh token.
  • The local runner (Agent) never gets the refresh token. It receives a live access token for the run and asks the server for a new one when it runs low.
  • Scheduled runs, packs and CI runs use the signed-in profile exactly as a manual run does. Nobody needs to be present.
  • Performance runs read authentication again while they run, so a long soak test keeps a valid token.

When a refresh fails

SituationWhat Studio does
The provider refuses the refresh (password changed, sign-in revoked, refresh token expired)Marks the profile Sign-in expired. Runs fail with "The sign-in for auth profile … has expired or was revoked. Open the profile and sign in again." It never sends a stale token.
The provider cannot be reached (network error, provider outage)Uses the current access token only while it is still valid; otherwise the run fails with a retryable error. The sign-in is not marked expired.
The provider issued no refresh tokenThe sign-in works until the access token expires. The panel says no refresh token (add offline_access to scopes).

Run analysis reports an expired sign-in as a single cause, The OAuth sign-in for "<profile name>" has expired, classed as an environment issue. It never suggests changing your tests, because the tests are not at fault.

Sign out, or sign in again

  • Sign out removes the stored tokens. If the profile has a Token Revocation URL, Studio also revokes the refresh token at the provider.
  • Sign in again replaces the current sign-in, for example to switch test accounts.
  • On the Authentication Profiles list, each interactive profile shows a badge: Not signed in, Signed in as …, or Sign-in expired.

Editing a signed-in profile

Changing a description or other details keeps the sign-in. Changing anything that decides which token you get (the flow, Client ID, Token URL, Authorization URL, Device Authorization URL or Scopes) drops the sign-in, and you must sign in again. If you edit the profile while a browser sign-in is in progress, the sign-in is refused with "The profile was edited while you were signing in. Save it, then sign in again."

Configure it with the Project Assistant

Ask the Project Assistant, for example, "Set up OAuth 2.0 browser sign-in for Entra tenant contoso.onmicrosoft.com with client ID … and scope api://orders/.default, then sign me in." It fills in the flow, URLs, client ID and scopes, reports the redirect URI you must register, and can start the browser or device sign-in. It will not accept a client secret or password in chat, because a secret typed into a conversation stays in the transcript; it opens the Authentication screen with the field marked instead. For a public client with no secret, the whole setup and sign-in can be done from the conversation.

Troubleshooting

SymptomWhy it happensWhat to do
The provider shows a redirect URI mismatch errorThe registered redirect URI differs from the one Studio shows.Copy the URI from the Browser sign-in panel and register it exactly. In Entra, use the platform shown in the table above.
Sign in with browser is disabled and a message mentions the public addressThe server installation has no public address configured.Ask an administrator to set it, or use Device Code.
"Interactive sign-in is switched off on this server"An administrator disabled interactive sign-in.Paste an access token, or ask the administrator.
invalid_client during sign-inWrong client authentication style, or a confidential client without its secret.Switch Client Authentication, or enter the Client Secret.
Signed in, but runs fail after about an hourNo refresh token was issued.Add offline_access to Scopes (for Google, use the preset) and sign in again.
Status shows Sign-in expiredThe provider revoked or expired the sign-in.Click Sign in again.
Runs return 401 even though signed inThe token lacks the scope or audience the API expects.Check Scopes, the Auth0 audience, or Additional Token Request Body (JSON).
"This sign-in link was already used" in the browserThe browser tab was reloaded after sign-in finished.Close it; if the panel is not signed in, start again.

Best practices

  • Use a dedicated test account, with the same MFA policy as real users, so tests reflect production behavior.
  • Always include offline_access (or your provider's equivalent) so scheduled runs keep working.
  • Set a Token Revocation URL so signing out really ends the session at the provider.
  • Keep one OAuth profile per environment and identity; do not switch accounts on a shared profile mid-sprint.
  • Sign in again well before a planned long run if the provider's refresh tokens have a fixed lifetime.

FAQ

Does Studio ever see my password? No. With browser and device sign-in, you type your password only on the provider's own page.

Do I need a client secret? Not for a public client using browser or device sign-in. Client Credentials (app only, no user) always needs one.

Who is the signed-in user when a teammate runs a test? The person who signed in to the profile. The sign-in belongs to the profile, not to whoever presses Run.

Does a duplicated profile keep the sign-in? No. Sign in to the duplicate separately.

Can I use this on the Desktop app offline from the provider? No. The provider must be reachable to sign in and to refresh tokens.

For administrators (self-hosted installations)

SettingDefaultWhat switching it does
PUBLIC_APP_URLnot setThe address people use to reach Studio. Required for browser sign-in on a server installation; the redirect URI is built from it.
OAUTH_REDIRECT_URInot setA full redirect URI override for installations behind a proxy that serves the API under a path. Must end in /api/oauth/callback.
OAUTH_INTERACTIVE_GRANTS_ENABLEDonfalse removes browser and device sign-in.
OAUTH_TOKEN_CACHE_ENABLEDonfalse fetches a new token for every request.
JWT_SECRET—Must be set; browser sign-in is refused without it.

Next steps

Still stuck?

Tell us what you’re trying to accomplish and we’ll point you to the right setup—installation, auth, or CI/CD wiring.