private void ExecuteFullAuth()
        {
            // Generate state and PKCE values.
            expectedState = CryptoUtils.RandomDataBase64Uri(32);
            codeVerifier  = CryptoUtils.RandomDataBase64Uri(32);
            var codeVerifierHash = CryptoUtils.Sha256(codeVerifier);
            var codeChallenge    = CryptoUtils.Base64UriEncodeNoPadding(codeVerifierHash);

            // Creates a redirect URI using an available port on the loopback address.
            redirectUri = string.Format("{0}:{1}", LOOPBACK_URI, GetRandomUnusedPort());

            // Listen for requests on the redirect URI.
            var httpListener = new HttpListener();

            httpListener.Prefixes.Add(redirectUri + '/');
            httpListener.Start();

            // Create the OAuth 2.0 authorization request.
            // https://developers.google.com/identity/protocols/OAuth2WebServer#creatingclient
            var authRequest = string.Format("{0}?response_type=code&scope={1}&redirect_uri={2}&client_id={3}&state={4}&code_challenge={5}&code_challenge_method={6}" +
                                            "&access_type=offline" +  // Forces to return a refresh token at the auth code exchange phase.
                                            "&approval_prompt=force", // Forces to show consent screen for each auth request. Needed to return refresh tokens on consequent auth runs.
                                            settings.AuthCredentials.AuthUri,
                                            settings.AccessScope,
                                            Uri.EscapeDataString(redirectUri),
                                            settings.AuthCredentials.ClientId,
                                            expectedState,
                                            codeChallenge,
                                            GoogleDriveSettings.CODE_CHALLENGE_METHOD);

            // Open request in the browser.
            Application.OpenURL(authRequest);

            // Wait for the authorization response.
            var context = httpListener.GetContext();

            // Send an HTTP response to the browser to notify the user to close the browser.
            var response       = context.Response;
            var responseString = settings.LoopbackResponseHtml;
            var buffer         = System.Text.Encoding.UTF8.GetBytes(responseString);

            response.ContentLength64 = buffer.Length;
            var responseOutput = response.OutputStream;

            responseOutput.Write(buffer, 0, buffer.Length);
            responseOutput.Close();
            httpListener.Stop();

            // Check for errors.
            if (context.Request.QueryString.Get("error") != null)
            {
                Debug.LogError(string.Format("UnityGoogleDrive: OAuth authorization error: {0}.", context.Request.QueryString.Get("error")));
                HandleProvideAccessTokenComplete(true);
                return;
            }
            if (context.Request.QueryString.Get("code") == null || context.Request.QueryString.Get("state") == null)
            {
                Debug.LogError("UnityGoogleDrive: Malformed authorization response. " + context.Request.QueryString);
                HandleProvideAccessTokenComplete(true);
                return;
            }

            // Extract the authorization code.
            authorizationCode = context.Request.QueryString.Get("code");
            var incomingState = context.Request.QueryString.Get("state");

            // Compare the receieved state to the expected value, to ensure that
            // this app made the request which resulted in authorization.
            if (incomingState != expectedState)
            {
                Debug.LogError(string.Format("UnityGoogleDrive: Received request with invalid state ({0}).", incomingState));
                HandleProvideAccessTokenComplete(true);
                return;
            }

            // Exchange the authorization code for tokens.
            authCodeExchanger.ExchangeAuthCode(authorizationCode, codeVerifier, redirectUri);
        }