No results for

Powered byAlgolia

OAuth Authentication

Scripting examples on how to use OAuth authentication in your load test.

OAuth authentication

The following examples take a set of arguments, shown in the function documentation, and returns the response body as JSON so that you can extract the token from.

Azure Active Directory

azure.js
1import http from 'k6/http';
2
3/**
4 * Authenticate using OAuth against Azure Active Directory
5 * @function
6 * @param {string} tenantId - Directory ID in Azure
7 * @param {string} clientId - Application ID in Azure
8 * @param {string} clientSecret - Can be obtained from https://docs.microsoft.com/en-us/azure/storage/common/storage-auth-aad-app#create-a-client-secret
9 * @param {string} scope - Space-separated list of scopes (permissions) that are already given consent to by admin
10 * @param {string} resource - Either a resource ID (as string) or an object containing username and password
11 */
12export function authenticateUsingAzure(tenantId, clientId, clientSecret, scope, resource) {
13 let url;
14 const requestBody = {
15 client_id: clientId,
16 client_secret: clientSecret,
17 scope: scope,
18 };
19
20 if (typeof resource == 'string') {
21 url = `https://login.microsoftonline.com/${tenantId}/oauth2/token`;
22 requestBody['grant_type'] = 'client_credentials';
23 requestBody['resource'] = resource;
24 } else if (
25 typeof resource == 'object' &&
26 resource.hasOwnProperty('username') &&
27 resource.hasOwnProperty('password')
28 ) {
29 url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
30 requestBody['grant_type'] = 'password';
31 requestBody['username'] = resource.username;
32 requestBody['password'] = resource.password;
33 } else {
34 throw 'resource should be either a string or an object containing username and password';
35 }
36
37 const response = http.post(url, requestBody);
38
39 return response.json();
40}

Azure B2C

The following example shows how you can authenticate with Azure B2C using the Client Credentials Flow.

This example is based on a JMeter example found at the azure-ad-b2c/load-tests repository.

To use this script, you need to:

  1. Set up your own Azure B2C tenant
    • Copy the tenant name, it will be used in your test script.
  2. Register a web application
    • Register a single page application with the redirect URL of: https://jwt.ms. That's needed for the flow to receive a token.
    • After the creation, you can get the Application (client) ID, and the Directory (tenant) ID. Copy both of them, they'll be used in your test script.
  3. Create a user flow so that you can sign up and create a user
    • Create a new user, and copy the username and password. They'll be used in the test script.

If you missed copying any of the settings, you can find them in the B2C settings in the Azure portal.

azure-b2c.js
1import http from "k6/http";
2import crypto from "k6/crypto";
3import { randomString } from "https://jslib.k6.io/k6-utils/1.2.0/index.js";
4
5const B2cGraphSettings = {
6 B2C: {
7 client_id: "", // Application ID in Azure
8 user_flow_name: "",
9 tenant_id: "", // Directory ID in Azure
10 tenant_name: "",
11 scope: "openid",
12 redirect_url: "https://jwt.ms",
13 },
14};
15
16/**
17 * Authenticate using OAuth against Azure B2C
18 * @function
19 * @param {string} username - Username of the user to authenticate
20 * @param {string} password
21 * @return {string} id_token
22 */
23export function GetB2cIdToken(username, password) {
24 const state = GetState();
25 SelfAsserted(state, username, password);
26 const code = CombinedSigninAndSignup(state);
27 return GetToken(code, state.codeVerifier);
28}
29
30/**
31 * @typedef {object} b2cStateProperties
32 * @property {string} csrfToken
33 * @property {string} stateProperty
34 * @property {string} codeVerifier
35 *
36 */
37
38/**
39 * Get the id token from Azure B2C
40 * @function
41 * @param {string} code
42 * @returns {string} id_token
43 */
44const GetToken = (code, codeVerifier) => {
45 const url =
46 `https://${B2cGraphSettings.B2C.tenant_name}.b2clogin.com/${B2cGraphSettings.B2C.tenant_id}` +
47 `/oauth2/v2.0/token` +
48 `?p=${B2cGraphSettings.B2C.user_flow_name}` +
49 `&client_id=${B2cGraphSettings.B2C.client_id}` +
50 `&grant_type=authorization_code` +
51 `&scope=${B2cGraphSettings.B2C.scope}` +
52 `&code=${code}` +
53 `&redirect_uri=${B2cGraphSettings.B2C.redirect_url}` +
54 `&code_verifier=${codeVerifier}`;
55
56 const response = http.post(url, "", {
57 tags: {
58 b2c_login: "GetToken",
59 },
60 });
61
62 return JSON.parse(response.body).id_token;
63};
64
65/**
66 * Signs in the user using the CombinedSigninAndSignup policy
67 * extraqct B2C code from response
68 * @function
69 * @param {b2cStateProperties} state
70 * @returns {string} code
71 */
72const CombinedSigninAndSignup = (state) => {
73 const url =
74 `https://${B2cGraphSettings.B2C.tenant_name}.b2clogin.com/${B2cGraphSettings.B2C.tenant_name}.onmicrosoft.com` +
75 `/${B2cGraphSettings.B2C.user_flow_name}/api/CombinedSigninAndSignup/confirmed` +
76 `?csrf_token=${state.csrfToken}` +
77 `&rememberMe=false` +
78 `&tx=StateProperties=${state.stateProperty}` +
79 `&p=${B2cGraphSettings.B2C.user_flow_name}`;
80
81 const response = http.get(url, "", {
82 tags: {
83 b2c_login: "CombinedSigninAndSignup",
84 },
85 });
86 const codeRegex = '.*code=([^"]*)';
87 return response.url.match(codeRegex)[1];
88};
89
90/**
91 * Signs in the user using the SelfAsserted policy
92 * @function
93 * @param {b2cStateProperties} state
94 * @param {string} username
95 * @param {string} password
96 */
97const SelfAsserted = (state, username, password) => {
98 const url =
99 `https://${B2cGraphSettings.B2C.tenant_name}.b2clogin.com/${B2cGraphSettings.B2C.tenant_id}` +
100 `/${B2cGraphSettings.B2C.user_flow_name}/SelfAsserted` +
101 `?tx=StateProperties=${state.stateProperty}` +
102 `&p=${B2cGraphSettings.B2C.user_flow_name}` +
103 `&request_type=RESPONSE` +
104 `&email=${username}` +
105 `&password=${password}`;
106
107 const params = {
108 headers: {
109 "X-CSRF-TOKEN": `${state.csrfToken}`,
110 },
111 tags: {
112 b2c_login: "SelfAsserted",
113 },
114 };
115 http.post(url, "", params);
116};
117
118/**
119 * Calls the B2C login page to get the state property
120 * @function
121 * @returns {b2cStateProperties} b2cState
122 */
123const GetState = () => {
124 const nonce = randomString(50);
125 const challenge = crypto.sha256(nonce.toString(), "base64rawurl");
126
127 const url =
128 `https://${B2cGraphSettings.B2C.tenant_name}.b2clogin.com` +
129 `/${B2cGraphSettings.B2C.tenant_id}/oauth2/v2.0/authorize?` +
130 `p=${B2cGraphSettings.B2C.user_flow_name}` +
131 `&client_id=${B2cGraphSettings.B2C.client_id}` +
132 `&nonce=${nonce}` +
133 `&redirect_uri=${B2cGraphSettings.B2C.redirect_url}` +
134 `&scope=${B2cGraphSettings.B2C.scope}` +
135 `&response_type=code` +
136 `&prompt=login` +
137 `&code_challenge_method=S256` +
138 `&code_challenge=${challenge}` +
139 `&response_mode=fragment`;
140
141 const response = http.get(url, "", {
142 tags: {
143 b2c_login: "GetCookyAndState",
144 },
145 });
146
147 const vuJar = http.cookieJar();
148 const responseCookies = vuJar.cookiesForURL(response.url);
149
150 const b2cState = {};
151 b2cState.codeVerifier = nonce;
152 b2cState.csrfToken = responseCookies["x-ms-cpim-csrf"][0];
153 b2cState.stateProperty = response.body.match('.*StateProperties=([^"]*)')[1];
154 return b2cState;
155};
156
157/**
158 * Helper function to get the authorization header for a user
159 * @param {user} user
160 * @returns {object} httpsOptions
161 */
162export const GetAuthorizationHeaderForUser = (user) => {
163 const token = GetB2cIdToken(user.username, user.password);
164
165 return {
166 headers: {
167 "Content-Type": "application/json",
168 Authorization: "Bearer " + token,
169 },
170 };
171};
172
173export default function () {
174 const token = GetB2cIdToken("zimmi.94@live.de", "20B2cTest23");
175 console.log(token);
176}

Okta

Okta-test.js
1import http from 'k6/http';
2import encoding from 'k6/encoding';
3
4/**
5 * Authenticate using OAuth against Okta
6 * @function
7 * @param {string} oktaDomain - Okta domain to authenticate against (e.g. 'k6.okta.com')
8 * @param {string} authServerId - Authentication server identifier (default is 'default')
9 * @param {string} clientId - Generated by Okta automatically
10 * @param {string} clientSecret - Generated by Okta automatically
11 * @param {string} scope - Space-separated list of scopes
12 * @param {string|object} resource - Either a resource ID (as string) or an object containing username and password
13 */
14export function authenticateUsingOkta(
15 oktaDomain,
16 authServerId,
17 clientId,
18 clientSecret,
19 scope,
20 resource
21) {
22 if (authServerId === 'undefined' || authServerId == '') {
23 authServerId = 'default';
24 }
25 const url = `https://${oktaDomain}/oauth2/${authServerId}/v1/token`;
26 const requestBody = { scope: scope };
27 let response;
28
29 if (typeof resource == 'string') {
30 requestBody['grant_type'] = 'client_credentials';
31
32 const encodedCredentials = encoding.b64encode(`${clientId}:${clientSecret}`);
33 const params = {
34 auth: 'basic',
35 headers: {
36 Authorization: `Basic ${encodedCredentials}`,
37 },
38 };
39
40 response = http.post(url, requestBody, params);
41 } else if (
42 typeof resource == 'object' &&
43 resource.hasOwnProperty('username') &&
44 resource.hasOwnProperty('password')
45 ) {
46 requestBody['grant_type'] = 'password';
47 requestBody['username'] = resource.username;
48 requestBody['password'] = resource.password;
49 requestBody['client_id'] = clientId;
50 requestBody['client_secret'] = clientSecret;
51
52 response = http.post(url, requestBody);
53 } else {
54 throw 'resource should be either a string or an object containing username and password';
55 }
56
57 return response.json();
58}

For a detailed example, please visit this article: How to Load Test OAuth secured APIs with k6?