Skip to main content

How to Test OAuth Secured APIs and Apps using JMeter

How to Test OAuth Secured APIs and Apps using JMeter

Key takeaways

  • Fetch the token once, in a setUp Thread Group, and share it through a JMeter property, so the timed requests measure the API and not the authorization server.
  • For a load test, use the client credentials grant with a dedicated test client. The password grant that older tutorials (including the screenshots below) use is now forbidden by the OAuth security best practice, RFC 9700.
  • Extract the token with a JSON Extractor, set it with a JSR223 (Groovy) element rather than BeanShell, and send it in an HTTP Header Manager as Authorization: Bearer <token>.
  • Tokens expire. Pick a token lifetime longer than the test, or refresh on purpose and keep the refresh out of the timed samples.

To load test an OAuth 2.0 secured API in JMeter, request an access token from the token endpoint with one HTTP Request, pull access_token out of the JSON response, store it where every thread can read it, and add it to each API call as a Bearer header. The steps below use Apache JMeter 5.6.3 (the current release, which needs Java 8 or newer).

How does OAuth 2.0 change a load test?

The API you want to measure no longer receives plain requests. Every call must carry an access token that the authorization server issued, and issuing tokens is work the server does too. If every virtual user requests its own token before every call, you are partly load testing the authorization server, and its response times get mixed into your API numbers. Decide which of the two you want to measure, and build the test plan for that one.

OAuth 2.0 authorization code flow: application, authorization server and resource server

The authorization code flow: the application gets a grant, trades it for an access token, then calls the resource server with it.

Which grant to script depends on who calls the API in production (RFC 6749 defines them):

GrantTypical callerFit for a load test
Client credentialsA backend service calling an APIBest fit: one POST to the token endpoint, no user and no browser
Authorization code (with PKCE, RFC 7636)Web, mobile and single-page apps acting for a userNeeds a user login and a redirect, so generate tokens ahead of the test (see below)
Resource owner passwordLegacy apps that collect the password themselvesDo not build new tests on it. RFC 9700 (January 2025) says it “MUST NOT be used”
ImplicitOld browser appsDo not use. RFC 9700 says clients “SHOULD NOT” use it

OAuth 2.1 would fold these rules into one document (PKCE for every authorization code flow, no implicit and no password grant), but it is still an Internet-Draft at the IETF (draft-ietf-oauth-v2-1, revision 16, September 2026), not an RFC. RFC 9700 is the published reference today.

How do I get an OAuth 2.0 token in JMeter?

Build the test plan in this order. JMeter’s own docs say setUp Thread Group threads “execute before the test proceeds to the executing of regular Thread Groups”, which is what makes it the right place for the token request. Regular thread groups run independently of each other, so a second group does not wait for the first.

Test Plan
  setUp Thread Group (1 thread, 1 loop)
    HTTP Request "Get token"
      HTTP Header Manager
      JSON Extractor
      JSR223 PostProcessor
  Thread Group "Load" (your users)
    HTTP Header Manager (Authorization: Bearer ${__P(token)})
    HTTP Request "GET /your-secured-endpoint"

Step 1: Request the token with an HTTP Request

Add a setUp Thread Group (Add > Threads (Users) > setUp Thread Group) with one thread and one loop, and an HTTP Request inside it. For the client credentials grant, the token endpoint expects a form-encoded POST (RFC 6749, section 4.4):

POST /oauth/token HTTP/1.1
Host: your-auth-server.example
Content-Type: application/x-www-form-urlencoded
Authorization: Basic <base64 of client_id:client_secret>

grant_type=client_credentials&scope=your-scope

In JMeter that is method POST, your token path, and grant_type and scope as parameters on the Parameters tab (an HTTP Header Manager under the sampler sets Content-Type: application/x-www-form-urlencoded). RFC 6749 (section 2.3.1) makes HTTP Basic the way a client authenticates to the token endpoint and allows the id and secret in the body only as a fallback it does not recommend, so use Basic unless your server only accepts the body form. Use a dedicated test client and keep the secret in a user-defined variable or a property passed with -J, not typed into the plan.

JMeter 5.3 test plan with a Get token request using the password grant

The token request in an older plan, screenshot from JMeter 5.3. It sends a JSON body with grant_type: password, which many servers still accept but which RFC 9700 now prohibits. Use client credentials, as above, for new tests.

Step 2: Extract the access token with a JSON Extractor

Under the token request, add Add > Post Processors > JSON Extractor. Set Names of created variables to access_token;expires_in and JSON Path expressions to $.access_token;$.expires_in. JMeter’s reference says both lists are semicolon separated and must have the same number of entries. Fill Default Values with TOKEN_NOT_FOUND;0 so a failed token request shows up as an obvious bad value instead of an empty header.

Step 3: Share the token with a JSR223 PostProcessor

Variables belong to one thread; JMeter properties are global and, in the manual’s words, “can be used to pass information between threads”. Add Add > Post Processors > JSR223 PostProcessor, set Language to groovy, and use:

props.put("token", vars.get("access_token"))

Older tutorials, including the first version of this one, use a BeanShell PostProcessor for this. JMeter’s documentation recommends moving from BeanShell to JSR223 with Groovy, for performance and because the BeanShell library has limited maintenance. The Groovy line does the same job.

Step 4: Send the token in an HTTP Header Manager

In the regular Thread Group that carries the load, add Add > Config Element > HTTP Header Manager with one header: name Authorization, value Bearer ${__P(token)}. __P reads a JMeter property. The Header Manager sits at the Thread Group level, so every request below it carries the header.

HTTP Header Manager in JMeter with Authorization: Bearer ${__P(token)}

The Authorization header reads the shared property. In this screenshot the plan is organised as two thread groups, token first, then data.

Step 5: Add the secured request and check it

Add an HTTP Request for the endpoint (GET /your-secured-endpoint) and an assertion such as a Response Assertion on status code 200. A 401 usually means the token is missing, malformed or expired, and a 403 means it is valid but lacks the scope. Run one thread with a View Results Tree first and read the real request: the header should show a long token, not TOKEN_NOT_FOUND. Remove the listener before the real run, and see the order JMeter executes elements in if a header or extractor does not seem to fire.

What happens when the token expires during the test?

Requests start returning 401 once the token’s expires_in seconds have passed, and the error rate jumps from that moment. You have three honest options:

  1. Use a longer-lived token for the test. Ask for a test client whose tokens outlive the run. This is the simplest option and keeps the numbers clean.
  2. Fetch a token per virtual user. Put the token request in the load Thread Group inside a Once Only Controller and keep the token in a variable (${access_token}) instead of a property. Be aware that each user then hits the token endpoint, so you are testing the authorization server as well. Report those timings separately.
  3. Refresh on a schedule. Store the expiry in a property (System.currentTimeMillis() + expires_in * 1000) and wrap a refresh request in an If Controller that fires shortly before it. Have one thread do it, not every thread at once, or the refresh itself becomes a spike.

Whatever you choose, name the token requests clearly, so you can filter them out of the response time report. The OAuth2 load testing guide covers the token side of this in more depth.

How do I load test an API behind the authorization code flow?

You cannot script the browser login with a few HTTP Requests, because the flow needs a user, a redirect and, with PKCE, a code verifier whose SHA-256 hash (the S256 method, RFC 7636) was sent in the first request. The practical approach is to separate the two problems. Issue a batch of test tokens ahead of the run, with a script or a test client that your authorization server permits, write them to a CSV file, and read one per thread with a CSV Data Set Config, as in how to use a CSV data set in JMeter. Each virtual user then sends its own Bearer ${token} header. That also gives you realistic per-user identities, where one shared token makes every request look like the same caller to rate limits and caches.

How do I keep credentials safe in a JMeter test plan?

Treat the plan, the .jtl result file and the JMeter log as places a secret can leak. Use a test client and test accounts, never production credentials. Pass the secret on the command line (-Jclient_secret=... and ${__P(client_secret)} in the plan) so it is not saved in the .jmx. Remember that a View Results Tree or a saved result with response data enabled records the token itself, and that tokens in a CI log stay there. Revoke or let the test client’s tokens expire when the run is done.

How do I run this test at scale?

Run it in non-GUI mode (jmeter -n -t plan.jmx -l results.jtl) with the secret passed in -J properties, and size the load by ramping threads up gradually, as described in JMeter’s ramp-up period. To generate load from several regions without managing load generators, LoadFocus runs JMeter scripts as they are from 25 cloud regions, with up to 20,000 concurrent virtual users per test on paid plans (loadfocus.com/load-testing, October 2026). See the LoadFocus JMeter load testing page for the details.

Frequently Asked Questions

How do I handle OAuth in a load test?

Do the token exchange before the measured requests. Otherwise you are load testing the auth server, and its timings get mixed into the numbers for the API you meant to test. In JMeter that means a setUp Thread Group that fetches the token and shares it through a property.

Which OAuth 2.0 grant should I use for a JMeter test?

Use client credentials for service-to-service APIs. For APIs behind a user login, pre-generate tokens through the authorization code flow with PKCE and feed them in from a CSV file. Avoid the password and implicit grants: RFC 9700 says the password grant must not be used and the implicit grant should not be.

What happens when the token expires mid-run?

Requests start failing with 401 unless you refresh it. Use a token that outlives the test, fetch a token per virtual user, or refresh from a single thread shortly before expiry.

Should I use BeanShell or JSR223 in JMeter?

JSR223 with Groovy. JMeter’s documentation recommends migrating from BeanShell for performance and because BeanShell has limited maintenance.

Are the credentials safe in the test plan?

Treat them as exposed. Tokens and credentials end up in logs and result files, so use test accounts rather than anything that touches real data, and pass secrets with -J instead of saving them in the plan.

Sources

Run this JMX in the cloud, from 25+ regions

Upload your JMeter script to LoadFocus and run it with thousands of virtual users from 25+ cloud locations, with no load generators to manage. Results show p95/p99 response times, throughput and errors per request, and a free tier is included.

JMeter Cloud Load Testing

Free API Load Test

Chris

Head of Content at LoadFocus

Chris leads content and oversees development across the services this blog covers. The guides and tool comparisons here come out of the same decisions that shape what ships.

Weekly tips right in your inbox.

Don’t miss out on the latest testing tips and tricks, tools and news related to software testing.

Already +20,000 members in the list.

The Load Testing Platform with AI That Explains Your Results

Load test websites and APIs from 25 cloud regions, monitor page speed and uptime, and get AI analysis that explains your results in plain English.

Cloud load testing, website speed and API monitoring in one place.

Hi there! Can I share a cool thing I'm working on with you?

A software testing newsletter that sparks joy.

Our goal is to create helpful content for software developers and testers.

If you're not into it, you can unsubscribe instantly.