diff --git a/lib/src/client.ts b/lib/src/client.ts
index 535f144d..96434055 100644
--- a/lib/src/client.ts
+++ b/lib/src/client.ts
@@ -197,14 +197,15 @@ export class AsgardeoAuthClient<T> {
     public async requestAccessToken(
         authorizationCode: string,
         sessionState: string,
+        state: string,
         userID?: string
     ): Promise<TokenResponse> {
         if (await this._dataLayer.getTemporaryDataParameter(OP_CONFIG_INITIATED)) {
-            return this._authenticationCore.requestAccessToken(authorizationCode, sessionState, userID);
+            return this._authenticationCore.requestAccessToken(authorizationCode, sessionState, state, userID);
         }
 
         return this._authenticationCore.getOIDCProviderMetaData(false).then(() => {
-            return this._authenticationCore.requestAccessToken(authorizationCode, sessionState, userID);
+            return this._authenticationCore.requestAccessToken(authorizationCode, sessionState, state,userID);
         });
     }
 
diff --git a/lib/src/constants/data.ts b/lib/src/constants/data.ts
index 04214175..1cb590b3 100644
--- a/lib/src/constants/data.ts
+++ b/lib/src/constants/data.ts
@@ -25,6 +25,7 @@ export enum Stores {
 
 export const REFRESH_TOKEN_TIMER = "refresh_token_timer";
 export const PKCE_CODE_VERIFIER = "pkce_code_verifier";
+export const PKCE_SEPARATOR = "#";
 
 export const SUPPORTED_SIGNATURE_ALGORITHMS = [
     "RS256", "RS512", "RS384", "PS256"
diff --git a/lib/src/constants/parameters.ts b/lib/src/constants/parameters.ts
index fca25c3b..f3d649d5 100644
--- a/lib/src/constants/parameters.ts
+++ b/lib/src/constants/parameters.ts
@@ -1,22 +1,23 @@
 /**
-* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
-*
-* WSO2 Inc. licenses this file to you under the Apache License,
-* Version 2.0 (the "License"); you may not use this file except
-* in compliance with the License.
-* You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*/
+ * Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * WSO2 Inc. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 
 export const AUTHORIZATION_CODE = "code";
 export const SESSION_STATE = "session_state";
 export const SIGN_OUT_URL = "sign_out_url";
 export const SIGN_OUT_SUCCESS_PARAM = "sign_out_success";
+export const STATE = "state";
diff --git a/lib/src/core/authentication-core.ts b/lib/src/core/authentication-core.ts
index 8f26c537..53573969 100644
--- a/lib/src/core/authentication-core.ts
+++ b/lib/src/core/authentication-core.ts
@@ -22,7 +22,8 @@ import {
     OP_CONFIG_INITIATED,
     PKCE_CODE_VERIFIER,
     SESSION_STATE,
-    SIGN_OUT_SUCCESS_PARAM
+    SIGN_OUT_SUCCESS_PARAM,
+    STATE
 } from "../constants";
 import { DataLayer } from "../data";
 import { AsgardeoAuthException, AsgardeoAuthNetworkException } from "../exception";
@@ -100,10 +101,13 @@ export class AuthenticationCore<T> {
             authorizeRequest.searchParams.append("response_mode", configData.responseMode);
         }
 
+        const pkceKey: string = await this._authenticationHelper.generatePKCEKey(userID);
+
         if (configData.enablePKCE) {
             const codeVerifier = this._cryptoHelper?.getCodeVerifier();
             const codeChallenge = this._cryptoHelper?.getCodeChallenge(codeVerifier);
-            await this._dataLayer.setTemporaryDataParameter(PKCE_CODE_VERIFIER, codeVerifier, userID);
+
+            await this._dataLayer.setTemporaryDataParameter(pkceKey, codeVerifier, userID);
             authorizeRequest.searchParams.append("code_challenge_method", "S256");
             authorizeRequest.searchParams.append("code_challenge", codeChallenge);
         }
@@ -121,12 +125,21 @@ export class AuthenticationCore<T> {
             }
         }
 
+        authorizeRequest.searchParams.append(
+            STATE,
+            AuthenticationUtils.generateStateParamForRequestCorrelation(
+                pkceKey,
+                authorizeRequest.searchParams.get(STATE) ?? ""
+            )
+        );
+
         return authorizeRequest.toString();
     }
 
     public async requestAccessToken(
         authorizationCode: string,
         sessionState: string,
+        state: string,
         userID?: string
     ): Promise<TokenResponse> {
         const tokenEndpoint = (await this._oidcProviderMetaData()).token_endpoint;
@@ -161,8 +174,17 @@ export class AuthenticationCore<T> {
         body.push(`redirect_uri=${ configData.signInRedirectURL }`);
 
         if (configData.enablePKCE) {
-            body.push(`code_verifier=${ await this._dataLayer.getTemporaryDataParameter(PKCE_CODE_VERIFIER, userID) }`);
-            await this._dataLayer.removeTemporaryDataParameter(PKCE_CODE_VERIFIER, userID);
+            body.push(
+                `code_verifier=${ await this._dataLayer.getTemporaryDataParameter(
+                    AuthenticationUtils.extractPKCEKeyFromStateParam(state),
+                    userID
+                ) }`
+            );
+
+            await this._dataLayer.removeTemporaryDataParameter(
+                AuthenticationUtils.extractPKCEKeyFromStateParam(state),
+                userID
+            );
         }
 
         return fetch(tokenEndpoint, {
diff --git a/lib/src/helpers/authentication-helper.ts b/lib/src/helpers/authentication-helper.ts
index 1f33f70f..9a5616bb 100644
--- a/lib/src/helpers/authentication-helper.ts
+++ b/lib/src/helpers/authentication-helper.ts
@@ -26,6 +26,8 @@ import {
     JWKS_ENDPOINT,
     OIDC_SCOPE,
     OIDC_SESSION_IFRAME_ENDPOINT,
+    PKCE_CODE_VERIFIER,
+    PKCE_SEPARATOR,
     REVOKE_TOKEN_ENDPOINT,
     SCOPE_TAG,
     SERVICE_RESOURCES,
@@ -43,6 +45,7 @@ import {
     FetchResponse,
     OIDCEndpointsInternal,
     OIDCProviderMetaData,
+    TemporaryData,
     TokenResponse
 } from "../models";
 import { AuthenticationUtils } from "../utils";
@@ -76,9 +79,9 @@ export class AuthenticationHelper<T> {
         if (configData.overrideWellEndpointConfig) {
             configData.endpoints &&
                 Object.keys(configData.endpoints).forEach((endpointName: string) => {
-                    const snakeCasedName = endpointName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
-                    oidcProviderMetaData[snakeCasedName] = configData?.endpoints
-                        ? configData.endpoints[endpointName]
+                    const snakeCasedName = endpointName.replace(/[A-Z]/g, (letter) => `_${ letter.toLowerCase() }`);
+                    oidcProviderMetaData[ snakeCasedName ] = configData?.endpoints
+                        ? configData.endpoints[ endpointName ]
                         : "";
                 });
         }
@@ -92,17 +95,17 @@ export class AuthenticationHelper<T> {
 
         configData.endpoints &&
             Object.keys(configData.endpoints).forEach((endpointName: string) => {
-                const snakeCasedName = endpointName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
-                oidcProviderMetaData[snakeCasedName] = configData?.endpoints ? configData.endpoints[endpointName] : "";
+                const snakeCasedName = endpointName.replace(/[A-Z]/g, (letter) => `_${ letter.toLowerCase() }`);
+                oidcProviderMetaData[ snakeCasedName ] = configData?.endpoints ? configData.endpoints[ endpointName ] : "";
             });
 
         const defaultEndpoints = {
-            [AUTHORIZATION_ENDPOINT]: configData.serverOrigin + SERVICE_RESOURCES.authorizationEndpoint,
-            [END_SESSION_ENDPOINT]: configData.serverOrigin + SERVICE_RESOURCES.endSessionEndpoint,
-            [JWKS_ENDPOINT]: configData.serverOrigin + SERVICE_RESOURCES.jwksUri,
-            [OIDC_SESSION_IFRAME_ENDPOINT]: configData.serverOrigin + SERVICE_RESOURCES.checkSessionIframe,
-            [REVOKE_TOKEN_ENDPOINT]: configData.serverOrigin + SERVICE_RESOURCES.revocationEndpoint,
-            [TOKEN_ENDPOINT]: configData.serverOrigin + SERVICE_RESOURCES.tokenEndpoint
+            [ AUTHORIZATION_ENDPOINT ]: configData.serverOrigin + SERVICE_RESOURCES.authorizationEndpoint,
+            [ END_SESSION_ENDPOINT ]: configData.serverOrigin + SERVICE_RESOURCES.endSessionEndpoint,
+            [ JWKS_ENDPOINT ]: configData.serverOrigin + SERVICE_RESOURCES.jwksUri,
+            [ OIDC_SESSION_IFRAME_ENDPOINT ]: configData.serverOrigin + SERVICE_RESOURCES.checkSessionIframe,
+            [ REVOKE_TOKEN_ENDPOINT ]: configData.serverOrigin + SERVICE_RESOURCES.revocationEndpoint,
+            [ TOKEN_ENDPOINT ]: configData.serverOrigin + SERVICE_RESOURCES.tokenEndpoint
         };
 
         return { ...oidcProviderMetaData, ...defaultEndpoints };
@@ -120,7 +123,7 @@ export class AuthenticationHelper<T> {
                     "validateIdToken",
                     "JWKS endpoint not found.",
                     "No JWKS endpoint was found in the OIDC provider meta data returned by the well-known endpoint " +
-                        "or the JWKS endpoint passed to the SDK is empty."
+                    "or the JWKS endpoint passed to the SDK is empty."
                 )
             );
         }
@@ -145,7 +148,7 @@ export class AuthenticationHelper<T> {
                 }
 
                 const issuer = (await this._oidcProviderMetaData()).issuer;
-                const issuerFromURL = (await this.resolveWellKnownEndpoint()).split("/.well-known")[0];
+                const issuerFromURL = (await this.resolveWellKnownEndpoint()).split("/.well-known")[ 0 ];
 
                 // Return false if the issuer in the open id config doesn't match
                 // the issuer in the well known endpoint URL.
@@ -155,7 +158,7 @@ export class AuthenticationHelper<T> {
                 const parsedResponse = await response.json();
 
                 return this._cryptoHelper
-                    .getJWKForTheIdToken(idToken.split(".")[0], parsedResponse.keys)
+                    .getJWKForTheIdToken(idToken.split(".")[ 0 ], parsedResponse.keys)
                     .then(async (jwk: any) => {
                         return this._cryptoHelper
                             .isValidIdToken(
@@ -218,12 +221,12 @@ export class AuthenticationHelper<T> {
         const familyName: string = payload.family_name ?? "";
         const fullName: string =
             givenName && familyName
-                ? `${givenName} ${familyName}`
+                ? `${ givenName } ${ familyName }`
                 : givenName
-                ? givenName
-                : familyName
-                ? familyName
-                : "";
+                    ? givenName
+                    : familyName
+                        ? familyName
+                        : "";
         const displayName: string = payload.preferred_username ?? fullName;
 
         return {
@@ -329,4 +332,27 @@ export class AuthenticationHelper<T> {
             return Promise.resolve(tokenResponse);
         }
     }
+
+    /**
+     * This generates a PKCE key with the right index value.
+     *
+     * @param {string} userID The userID to identify a user in a multi-user scenario.
+     *
+     * @returns {string} The PKCE key.
+     */
+    public async generatePKCEKey(userID?: string): Promise<string> {
+        const tempData: TemporaryData = await this._dataLayer.getTemporaryData(userID);
+        const keys: string[] = [];
+
+        Object.keys(tempData).forEach((key: string) => {
+            if (key.startsWith(PKCE_CODE_VERIFIER)) {
+                keys.push(key);
+            }
+        });
+
+        const lastKey: string | undefined = keys.sort().pop();
+        const index: number = parseInt(lastKey?.split(PKCE_SEPARATOR)[ 1 ] ?? "-1");
+
+        return `${ PKCE_CODE_VERIFIER }${ PKCE_SEPARATOR }${ index + 1 }`;
+    }
 }
diff --git a/lib/src/public-api.ts b/lib/src/public-api.ts
index 1abd6e14..9c220332 100644
--- a/lib/src/public-api.ts
+++ b/lib/src/public-api.ts
@@ -24,3 +24,4 @@ export * from "./constants/parameters";
 export * from "./constants/data";
 export * from "./constants/parameters";
 export * from "./constants/scopes";
+export * from "./utils";
diff --git a/lib/src/utils/authentication-utils.ts b/lib/src/utils/authentication-utils.ts
index b8e6defa..3da23998 100644
--- a/lib/src/utils/authentication-utils.ts
+++ b/lib/src/utils/authentication-utils.ts
@@ -16,6 +16,7 @@
  * under the License.
  */
 
+import { PKCE_CODE_VERIFIER, PKCE_SEPARATOR } from "../constants";
 import { DecodedIDTokenPayload } from "../models";
 
 export class AuthenticationUtils {
@@ -78,4 +79,24 @@ export class AuthenticationUtils {
             "Content-Type": "application/x-www-form-urlencoded"
         };
     }
+
+    /**
+     * This generates the state param value to be sent with an authorization request.
+     *
+     * @param {string} pkceKey The PKCE key.
+     * @param {string} state The state value to be passed. (The correlation ID will be appended to this state value.)
+     *
+     * @returns {string} The state param value.
+     */
+    public static generateStateParamForRequestCorrelation(pkceKey: string, state?: string): string {
+        const index: number = parseInt(pkceKey.split(PKCE_SEPARATOR)[ 1 ]);
+
+        return state ? `${ state }_request_${ index }` : `request_${ index }`;
+    }
+
+    public static extractPKCEKeyFromStateParam(stateParam: string): string {
+        const index: number = parseInt(stateParam.split("request_")[ 1 ]);
+
+        return `${ PKCE_CODE_VERIFIER }${ PKCE_SEPARATOR }${ index }`;
+    }
 }