How to make source code from CQDPowerShell cmdlet acquiring access token non-interactively

Copper Contributor

We are trying to implement similar to code taken from CQDPowerShell and re-written in C# in our .Net application. But we do not find a way how to make non-interactive access/refresh token acquisition instead of interactive access token acquisition with popup window with entering credentials . We find only how to get access token in the PowerShell cmdlet CQDPowerShell and the access token lives only 1 hour. Then the access token have to acquired interactively again.  While we need to have the code running indefinitely without the user interaction.

 

string redirectUrl = System.Web.HttpUtility.UrlEncode("https://cqd.teams.microsoft.com/spd/");
string resourceUrl = System.Web.HttpUtility.UrlEncode("https://cqd.teams.microsoft.com");
string clientId = "c61d67cf-295a-462c-972f-33af37008751";
 
string url = $"https://login.microsoftonline.com/common/oauth2/authorize?response_type=token&redirect_uri={redirectUrl}&client_id={clientId}" +
                $"&prompt=login&nonce=$nonce&resource={resourceUrl}";
 
Form form = new Form { Width = 440, Height = 640 };
WebBrowser web = new WebBrowser { Width = 420, Height = 600, Url = new Uri(url) };
 
web.DocumentCompleted += (sender, e) =>
{
      string uri = web.Url.AbsoluteUri;
      if (Regex.Match(uri, "error=[^&]*|access_token=[^&]*|code=[^&]*").Success)
      {
                    form.Close();
      }
};
 
web.ScriptErrorsSuppressed = true;
form.Controls.Add(web);
form.Shown += (sender, e) =>
{
       form.Activate();
};
 
form.ShowDialog();
 
string responseUrl = web.Url.ToString();
 
int codeStartIndex = responseUrl.IndexOf("access_token=") + "access_token=".Length;
int codeEndIndex = responseUrl.IndexOf("&");
string code = responseUrl.Substring(codeStartIndex, codeEndIndex - codeStartIndex);

The code above retrieves access code, as well as possible to retrieve "access code", by replacing "response_type=token" into "response_type=code". But do not know how to use that "access code".

 

We need this API to retrieve Teams Call Quality Dashboard statistics. Maybe there are other APIs to retrieve Teams Call Quality statistics?

9 Replies

@Oleksii_Kolinko 

Please find the code here in gitrepo. 

here we used loop the access code to generate each time for the requirement.

Token1, Token2, Token3 will generate in each request.

 

Please find the code for getting Refresh token. Use this function to call each time to retrieve or get the access token.

Please check above solutions and let us know if you need any thing.

@teams1535 

 

First example works with client secret, which in this case is not availible.

 

While according to seconds example I written the code, which should theoretically return access token out of "authorization code":

using (HttpClient httpClient = new HttpClient())
            {
                string newRequestPath = $"https://login.microsoftonline.com/<tenant guid>/oauth2/v2.0/token";
 
                string requestBOdy = $"grant_type=authorization_code&client_id={clientId}&redirect_uri={redirectUrl}&code={code}";
 
                HttpContent httpContent = new StringContent(requestBOdy, Encoding.UTF8, "application/x-www-form-urlencoded");
 
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, newRequestPath);
                request.Content = httpContent;
 
                Task<HttpResponseMessage> response = httpClient.SendAsync(request);
                response.Wait();
 
                Task<string> responseString = response.Result.Content.ReadAsStringAsync();
                responseString.Wait();
 
 
            }

 But it returns the following error message:

 

"{\"error\":\"invalid_client\",\"error_description\":\"AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'.\\r\\nTrace ID: d89e74e1-36dd-4807-9c51-dda7003c0700\\r\\nCorrelation ID: eb4c20b0-7ab5-41c4-a7b3-3d793e6de0b6\\r\\nTimestamp: 2020-04-24 12:07:16Z\",\"error_codes\":[7000218],\"timestamp\":\"2020-04-24 12:07:16Z\",\"trace_id\":\"d89e74e1-36dd-4807-9c51-dda7003c0700\",\"correlation_id\":\"eb4c20b0-7ab5-41c4-a7b3-3d793e6de0b6\",\"error_uri\":\"https://login.microsoftonline.com/error?code=7000218\"}"

I have contacted the owner of the PowerShell cmdlet, he told me that there is no non-interactive way of getting the access token.

hi there :)

@Oleksii_Kolinko just wondering if you have found a way to do non-interactive login on the CQDPowerShell module.

 

thanks,

Ed

I did not found the way. It does not exist. I got a response from a developer of the module.

Hi @Oleksii_Kolinko. Do you know if there´s a way to request to the developers of the CQD to enable the option "Allow public client flows" for the Microsoft Application: Call Quality Dashboard, Client Id: c61d67cf-295a-462c-972f-33af37008751?

For the moment, I already voted to your request in Teams User Voice:

https://microsoftteams.uservoice.com/forums/555103-public/suggestions/40344751-make-api-for-teams-ca...

Thanks.

@jonvasbar 

I tried passing credentials to Invoke-WebRequest (Similar issue to https://docs.microsoft.com/en-us/answers/questions/290269/invoke-webrequest-to-get-access-token-for-...), but this did not get the token (in $response.content). What else do I need to add to this code to get the token?

 

$AdminName = "r987327"
$Pass = Get-Content "encrypted_pass.txt" | ConvertTo-SecureString
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $AdminName, $Pass
$configRest = Invoke-RestMethod -Uri "https://cqd.teams.microsoft.com/repository/clientconfiguration" -Method Get -SessionVariable WebSession -UserAgent "CQDPowerShell V2.0"
$WebResource = $configRest.AuthLoginResource
$client_id = $configRest.AuthWebAppClientId
Add-Type -AssemblyName System.Web
$resourceUrl = $WebResource
$redirectUrl = "https://cqd.teams.microsoft.com/spd/"
$nonce = [guid]::NewGuid().GUID
$url = "https://login.microsoftonline.com/common/oauth2/authorize?response_type=token&redirect_uri=" + [System.Web.HttpUtility]::UrlEncode($redirectUrl) + "&client_id=$client_id" + "&prompt=login" + "&nonce=$nonce" + "&resource=" + [System.Web.HttpUtility]::UrlEncode($WebResource)
$response = Invoke-WebRequest -Uri $url -Method GET -Headers @{Metadata="true"}  -Credential $cred

@hdsouza1 Did you get any further with this attempt? I recently managed to use the "CustomFilter" but am still stuck with passing credentials. Perhaps you have solved it?

Sorry. I could not pass credentials either. We even opened a case with Microsoft to support this with an enhancement request but that is still in limbo.