DEV Community

Cover image for How to Test OAuth 2.0 APIs in Apidog (Authorization Code, Client Credentials, and Token Refresh)
Hassann
Hassann

Posted on Originally published at apidog.com

How to Test OAuth 2.0 APIs in Apidog (Authorization Code, Client Credentials, and Token Refresh)

Every API team hits the same wall: endpoints work in isolation, then OAuth 2.0 enters the picture and half the test suite starts returning 401. Suddenly, you’re juggling authorization servers, short-lived access tokens, and manually copying tokens from curl responses into headers.

Try Apidog today

The solution isn’t skipping authentication in your tests. It’s making token handling part of test setup. This guide covers the two OAuth flows you’ll use most often:

  • Authorization code with PKCE for APIs acting on behalf of a user
  • Client credentials for machine-to-machine calls

For a complete overview of OAuth grants, see OAuth 2.0 flows overview.

You’ll also learn how to configure OAuth 2.0 in Apidog, reuse tokens, refresh expired tokens, inherit authentication at the folder level, and test authentication failures.

The two OAuth flows that matter for API testing

OAuth 2.0 defines several grant types, but day-to-day API testing usually centers on one question:

Does the API act on behalf of a user or a service?

Authorization code flow with PKCE

The authorization code flow obtains a token tied to a user:

  1. The client redirects the user to the authorization server.
  2. The user logs in and grants consent.
  3. The authorization server redirects back with a one-time code.
  4. The client exchanges the code for an access token at the token endpoint.

RFC 6749 defines this flow in section 4.1.

PKCE (Proof Key for Code Exchange, RFC 7636) protects the code exchange. The client generates a random verifier, sends a hashed challenge with the authorization request, then proves possession of the verifier when redeeming the code. An attacker who intercepts the code cannot use it.

PKCE was originally designed for mobile apps, but oauth.net recommends it for every authorization code exchange, including confidential clients.

Use this flow when endpoint behavior depends on user identity, such as:

  • GET /orders returning only the caller’s orders
  • Role-protected admin endpoints
  • Per-user rate limits

Client credentials flow

The OAuth 2.0 client credentials grant skips the user. The client authenticates with its own ID and secret and receives a token representing the application:

curl -X POST https://auth.example.com/oauth/token \
  -d grant_type=client_credentials \
  -d client_id=orders_service \
  -d [REDACTED CREDENTIAL] \
  -d scope="orders:read orders:write"
Enter fullscreen mode Exit fullscreen mode

Use client credentials for machine-to-machine APIs, including:

  • Internal microservices
  • Cron jobs
  • CI pipelines calling deployment APIs
  • Most automated test suites

If your test environment can provision a test client, use client credentials unless user identity is the behavior under test.

Configure OAuth 2.0 authentication in Apidog

Apidog treats OAuth 2.0 as a first-class authentication type. Configure it once in the Auth tab for a request or folder, and Apidog handles token retrieval, attachment, and refresh.

Supported grant types include:

  • Authorization Code
  • Authorization Code (With PKCE)
  • Client Credentials
  • Password Credentials
  • Implicit

The examples below use a fictional order-management API.

Configure client credentials

Open a request—or preferably its folder—set the authentication type to OAuth 2.0, and select Client Credentials.

Enter:

  • Access Token URL: https://auth.example.com/oauth/token
  • Client ID: orders_service
  • **Client [REDACTED CREDENTIAL] Your provisioned secret
  • Scope: orders:read orders:write under advanced options

Apidog can send credentials in either:

  • A Basic Auth header
  • The request body

Match the option expected by your authorization server. Auth0 and Okta accept both, while some internal authorization servers only parse credentials from the body.

Click Get Token. Apidog calls the token endpoint, stores the response, and displays the token and validity period. Subsequent requests automatically send:

[REDACTED CREDENTIAL] <access-token>
Enter fullscreen mode Exit fullscreen mode

No copy-paste or {{token}} variable plumbing is required.

Configure authorization code with PKCE

For user-context testing, select Authorization Code (With PKCE). In Apidog, PKCE is a separate grant option rather than a checkbox.

Enter:

  • Auth URL: https://auth.example.com/oauth/authorize
  • Access Token URL: https://auth.example.com/oauth/token
  • Callback URL: The redirect URI registered with your provider
  • **Client ID and Client [REDACTED CREDENTIAL] From your OAuth app registration

Click Get Token. Apidog opens a browser window to the login page. Sign in with your test user, approve the consent screen, and Apidog stores the returned token in the same managed token slot.

If your provider returns an OpenID Connect ID token alongside the access token, use Token Type Used to choose which token Apidog attaches. This is useful when the API validates ID tokens.

Create a dedicated test user for each role you need to cover, such as:

  • Buyer
  • Administrator
  • Read-only auditor

Fetching a token for each user and rerunning the same scenario is a fast way to verify role-based access rules.

Reuse and automatically refresh tokens

Access tokens commonly expire within an hour. An expired token should not turn into a mysterious or flaky test failure.

When the authorization server issues a refresh token, Apidog automatically refreshes the access token after expiry. This capability shipped in the June update.

Apidog uses the refresh token to request a new access token and replaces the stored token before sending the request. If your provider separates refresh operations into another endpoint, configure a custom refresh token URL in advanced settings.

Client credentials flows often do not return refresh tokens because the client can authenticate again at any time. In that case:

  • Click Get Token to request a new token
  • Configure scheduled or CI runs to request a token at the beginning of each run

Inherit authentication at the folder level

Configuring OAuth separately on every request creates unnecessary maintenance. Instead, set OAuth 2.0 on a folder and let child requests inherit the configuration.

For example, configure OAuth once on an Orders API folder. Every request inside it—including requests added later—uses the same managed token.

Folder-level authentication is especially useful for multi-step scenarios:

POST /carts
POST /carts/{id}/items
POST /orders
Enter fullscreen mode Exit fullscreen mode

All steps share one token and one configuration. Automatic refresh handles token expiry during the scenario, and rotating a client secret requires updating only the folder instead of dozens of requests.

Individual requests can override the inherited configuration, which is useful for negative tests.

Test OAuth failure paths

Happy-path tests verify that your token pipeline works. Failure-path tests verify that your API enforces authentication and authorization.

For a refresher on status-code behavior, see API keys and Bearer [REDACTED].

Expired or missing [REDACTED CREDENTIAL] 401

Duplicate a request and override its inherited authentication with either:

  • No authentication
  • A hardcoded expired token, such as Bearer [REDACTED]

Assert that:

  • The status code is 401
  • The WWW-Authenticate response header is present
  • The response body does not expose stack traces or internal hostnames

A 200 response is a critical bug. A 403 is a design smell: the server should distinguish between “I don’t know who you are” and “I know who you are, but you are not allowed.”

Incorrect scope: expect 403

Provision a second test client limited to orders:read. Fetch its token and call a write endpoint such as POST /orders.

Assert that:

  • The status code is 403
  • If your API follows RFC 6750, the WWW-Authenticate header contains error="insufficient_scope"

This catches configurations where scope checks are enforced on some routes but omitted on others. For more background, see OAuth 2.0 scopes explained.

Invalid client: expect a token-endpoint error

Send a request directly to:

https://auth.example.com/oauth/token
Enter fullscreen mode Exit fullscreen mode

Use an invalid client_secret. Under RFC 6749 section 5.2, the authorization server should return either:

  • 400, or
  • 401 for failed client authentication

The JSON response should contain:

{
  "error": "invalid_client"
}
Enter fullscreen mode Exit fullscreen mode

Assert on both the status code and error field. Authorization servers are APIs too, so their error contracts belong in your test coverage.

Assert token responses in test scenarios

The token endpoint deserves coverage beyond invalid-client handling. Add a scenario step that calls the token endpoint directly, then assert that:

  • access_token exists and is non-empty
  • token_type equals bearer, case-insensitively
  • expires_in is greater than 0 and within policy, such as no more than 3600
  • scope matches the requested scope

These checks catch authorization servers that silently narrow grants or return malformed responses.

Apidog test scenarios support visual assertions on response JSON without scripting. You can also extract access_token into a variable for a follow-up request when testing the raw OAuth handshake instead of managed authentication.

Run the scenario in CI so an authorization-server regression fails the build rather than appearing as a mysterious 401 in production.

A practical test structure looks like this:

  1. Configure OAuth 2.0 at the folder level for happy-path requests.
  2. Override authentication per request for 401 and 403 cases.
  3. Add a scenario that validates the token endpoint contract.
  4. Run the scenario in CI.

This covers user-context APIs with authorization code and PKCE, service-to-service APIs with client credentials, and token refresh without manual intervention. Download Apidog and try it free. OAuth 2.0 authentication is available on the free plan.

FAQ

Which OAuth flow should I use for API testing?

Use client credentials for machine-to-machine APIs and most automated suites because it requires no browser interaction.

Use authorization code with PKCE when tests depend on user identity, including:

  • Per-user data isolation
  • Role checks
  • Consent behavior

Avoid implicit and password grants in new test plans; both are discouraged in current OAuth guidance.

How do I refresh an expired token automatically in Apidog?

Configure OAuth 2.0 in the Auth tab and click Get Token. When the authorization server returns a refresh token, Apidog refreshes the access token after expiry without requiring you to authenticate again.

If your provider uses a separate refresh endpoint, configure its URL in advanced settings. For client credentials flows without refresh tokens, click Get Token again to issue a fresh token.

Can every request in a scenario share one OAuth token?

Yes. Configure OAuth 2.0 on the parent folder, and child requests inherit the managed token.

Individual requests can override the folder configuration, allowing you to add expired-token and insufficient-scope tests to the same scenario.

What should 401 versus 403 mean in OAuth-protected APIs?

Return 401 when authentication fails because the token is missing, expired, or malformed.

Return 403 when the token is valid but lacks permission, such as a required scope.

Mixing up these status codes breaks client retry logic:

  • 401 tells the client to authenticate again
  • 403 tells the client to stop retrying

For token-validation coverage, see testing JWT authentication.

Top comments (0)