Hi,
I am trying to get a token using OAuth2 from a web app. I am able to do it using the /authorize endpoint if using response_type=token. However, this returns the token in plan text in the redirect url which I find a bit low security. I guess it is in the user's own browser, so perhaps not that big a deal.
I thought I would try to use the approach of getting an authorization code and then use the /token endpoint to get the token. However, I am unable to retrieve this successfully.
Initially I send the /authorize request
string authorizeUrl = "https://www.arcgis.com/sharing/rest/oauth2/authorize";
string clientId = "my-client-id";
string redirectUrl = "https://localhost:7109/counter";
string responseType = "code";
string codeChallenge = "12345";
string codeChallengeMethod = "plain";
Console.WriteLine($"Index Challenge: {codeChallenge}");
$"{authorizeUrl}?client_id={clientId}&redirect_uri={redirectUrl}&response_type={responseType}&code_challenge={codeChallenge}&code_challenge_method={codeChallengeMethod}";
UriBuilder builder = new UriBuilder(authorizeUrl)
{
Query = $"client_id={clientId}&redirect_uri={redirectUrl}&response_type={responseType}&code_challenge={codeChallenge}&code_challenge_method={codeChallengeMethod}"
};
string oAuthUrl = builder.ToString();
NavigationManager.NavigateTo(oAuthUrl);
This works perfect and takes me to the login page and when I login I am then redirected correctly to redirect page and the code is attached.
So then a post request is made to get the /token endpoint
//this gets the returned code, I have validated that it matches when is in the redirect Url
string code = Navigation.Uri.Substring(Navigation.Uri.IndexOf("=", StringComparison.Ordinal) + 1);
string tokenUrl = "https://www.arcgis.com/sharing/rest/oauth2/token";
string clientId = "my-client-id";
string redirectUrl = "https://localhost:7109/counter";
//string codeChallenge = CreateSHA256Challenge();
string codeChallenge = "12345";
var dictionary = new Dictionary<string, string>
{
{"client_id", clientId},
{"grant_type", "authorization_code"},
{"code", code!},
{"code_verifier", codeChallenge},
{"redirect_uri", redirectUrl}
};
FormUrlEncodedContent content = new FormUrlEncodedContent(dictionary);
using HttpClient client = new HttpClient();
var response = await client.PostAsync(tokenUrl, content);
var json = await response.Content.ReadAsStringAsync();
However, this fails and returns
{
"error": {
"code": 400,
"error": "invalid_request",
"error_description": "Invalid PKCE code_challenge_verifier",
"message": "Invalid PKCE code_challenge_verifier",
"details": []
}
}
The example I am just using a very simple challenge in plain text to make this as easy as possible to validate.
Is there something I am missing in the /token request? One thing I find odd is you do not need to specify if is plain or S256 in the /token request. The /token post call is within milliseconds of the initial /authorize request so nothing could have expired.
Does anyone has thoughts on what I am missing?
Thanks - Joe