I have checked every thing repeatedly and does not seem to have any issue in code or logic.
Here is the code:
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{"grant_type", "authorization_code"},
{"code", code},
{"redirect_uri", redirectUri.ToString()},
{"client_id", clientId},
{"client_secret", clientSecret}
});
string token = string.Empty;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
var response = client.PostAsync(tokenEndpoint, content);
var responseContent = response.Result.Content.ReadAsStringAsync();
token = responseContent.ToString();
if (!response.Result.IsSuccessStatusCode) ;
}
return token;
And i am getting error:
"error": "redirect_uri_mismatch",
"error_description": "Bad Request"
The Url of the above page is : http://localhost:62188/dashboard/googleSync.aspx
And in Google Console i have this Url as Authorized Return Url :
So what am i missing here?
Ok: had to use this : :redirect_uri = "postmessage" and it worked.
Related
I have a customer API endpoint (POST) that works fine from postman.
The Postman settings using which I am able to receive response is like this:
URL:
https://somedomain.com/rest/portal/authenticate
Headers:
"Content-Type":"application/x-www-form-urlencoded"
"Referrer": "10.xx.xx.xx" // Real IP address here
Body: (x-www-form-urlencoded)
"username": "TestAdmin"
"password": "testpassword"
This setting works fine and I am able to get response in postman.
Now from the same laptop, I tried to make a POST call from .Net core 3.1 method. I have tried with this code:
string userName = _config.GetSection("username").Value;
string Password = _config.GetSection("password").Value;
string BaseURL = _config.GetSection("baseURL").Value; // https://somedomain.com/rest
var dict = new Dictionary<string, string>();
dict.Add("username", userName);
dict.Add("password", Password);
var client = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, BaseURL + $"/portal/authenticate")
{ Content = new FormUrlEncodedContent(dict) };
req.Headers.Add("Referer", "10.xx.xx.xx"); // real IP address entered here
var response = client.SendAsync(req).Result;
string responseContent = response.Content.ReadAsStringAsync().Result;
With this approach I am getting Bad request error with "Inavlid user" message.
What am I doing wrong here? Is the request I have built is not same as Postman ?
Once you populate the data in dictionary, build a payload out of it which conforms to
application/x-www-form-urlencoded content type.
var dict = new Dictionary<string, string>();
dict.Add("username", userName);
dict.Add("password", Password);
string payload = BuildPayload(dic);
Function BuildPayload is defined to form the entire uri from dictionary objects :
private string BuildPayload(Dictionary<string, string> dic)
{
StringBuilder builder = new StringBuilder();
int i = 0;
foreach (var item in dic)
{
if (i > 0)
builder.Append("&");
builder.AppendFormat("{0}={1}", item.Key, item.Value);
i++;
}
return builder.ToString();
}
Then you can get create StringContent instance which will provide you http content based on created payload string. If you need encoding pass it as second param otherwise leave it as null.
StringContent request = new StringContent(payload, null, "application/x-www-form-urlencoded");
Then append your custom header with httpclient instance and call the api with the defined request.
httpClient.DefaultRequestHeaders.Add("Referrer","10.xx.xx.xx");
HttpResponseMessage response = await httpClient.PostAsync(<Your api url>, request);
if (response.IsSuccessStatusCode)
{
string resultStr = await response.Content.ReadAsStringAsync();
}
I am using Botframework adaptive dialog template (c#). I already obtained a token from a HttpRequest and saved it as a conversation state property conversation.token, now I am trying to use this token to make another API call with HttpRequest. But from the official document of HttpRequest Class, it seems there is no options to add the authentication token. I tried to add the token in the Headers, but did not work, it showed 401 Unauthorized error. How should the authorization be handled in HttpRequest in adaptive dialog?
new HttpRequest()
{
Url = "http://example.com/json",
ResultProperty = "conversation.httpResponse",
Method = HttpRequest.HttpMethod.GET,
ResponseType = HttpRequest.ResponseTypes.Json,
Headers = new Dictionary<string, AdaptiveExpressions.Properties.StringExpression>()
{
{"Authorization", "Bearer ${conversation.token.content.token}"},
},
},
new SendActivity("${conversation.httpResponse}"),
Instead of using HttpRequest, I made the API call inside CodeAction with custom code.
First make a POST request to get the token, then make a GET request to call the main API. In the GET request, the authorization can be added in this way: client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);.
new CodeAction(async (dc, options) =>
{
var my_jsondata = new
{
Username = "username",
Password = "password"
};
var json = JsonConvert.SerializeObject(my_jsondata);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var Tokenurl = "https://example.com/token?HTTP/1.1";
using var Tokenclient = new HttpClient();
var Tokenresponse = await Tokenclient.PostAsync(Tokenurl, data);
string Toeknresult = Tokenresponse.Content.ReadAsStringAsync().Result;
var Tokenjo = JObject.Parse(Tokenresult);
using var client = new HttpClient();
var url = "https://example.com/mainapi?HTTP/1.1";
var accessToken = Tokenjo["token"];
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var response = await client.GetAsync(url);
string result = response.Content.ReadAsStringAsync().Result;
dc.State.SetValue("conversation.httpresponse", response);
dc.State.SetValue("conversation.result", result);
return await dc.EndDialogAsync();
}),
I'm trying to make a simple request to the Basecamp API, I'm following the instructions provided adding in a sample user agent and my credentials yet I keep getting a 403 Forbidden response back.
My credentials are definitely correct so is it a case of my request/credentials being set incorrectly?
This is what I have (removed personal info):
var httpClient = new HttpClient();
var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("User-Agent", "MyApp [EMAIL ADDRESS]") });
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "[USERNAME]", "[PASSWORD]"))));
var response = await httpClient.PostAsync("https://basecamp.com/[USER ID]/api/v1/projects.json", content);
var responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
Console.WriteLine(await reader.ReadToEndAsync());
}
A quick look over their documentation seems to indicate that the projects.json endpoint accepts the following in the body of the POST:
{
"name": "This is my new project!",
"description": "It's going to run real smooth"
}
You're sending the User-Agent as the POST body. I'd suggest you change your code as follows:
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "[USERNAME]", "[PASSWORD]")));
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp [EMAIL ADDRESS]");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
var response = await httpClient.PostAsJsonAsync(
"https://basecamp.com/[USER ID]/api/v1/projects.json",
new {
name = "My Project",
description = "My Project Description"
});
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}
This posts the payload as specified in the docs and sets your user agent in the headers as it should be.
I have previously been adding users programmatically using Active Directory Authentication Library (ADAL), but now I need to define "signInNames" (= users email), and that doesn't seem to be possible with ADAL (please tell me if im wrong).
Now I'm trying to add a new user (local account) programmatically using HTTP POST, following the documentation on MSDN.
//Get access token (using ADAL)
var authenticationContext = new AuthenticationContext(AuthString, false);
var clientCred = new ClientCredential(ClientId, ClientSecret);
var authenticationResult = authenticationContext.AcquireTokenAsync(ResourceUrl, clientCred);
var token = authenticationResult.Result.AccessToken;
//HTTP POST CODE
const string mail = "new#email.com";
// Create a new user object.
var user = new CustomUser
{
accountEnabled = true,
country = "MS",
creationType = "LocalAccount",
displayName = mail,
passwordPolicies = "DisablePasswordExpiration,DisableStrongPassword",
passwordProfile = new passwordProfile { password = "jVPmEm)6Bh", forceChangePasswordNextLogin = true },
signInNames = new signInNames { type = "emailAddress", value = mail }
};
var url = "https://graph.windows.net/" + TenantId + "/users?api-version=1.6";
var jsonObject = JsonConvert.SerializeObject(user);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = client.PostAsync(url,
new StringContent(JsonConvert.SerializeObject(user).ToString(),
Encoding.UTF8, "application/json"))
.Result;
if (response.IsSuccessStatusCode)
{
dynamic content = JsonConvert.DeserializeObject(
response.Content.ReadAsStringAsync()
.Result);
// Access variables from the returned JSON object
var appHref = content.links.applications.href;
}
}
But i have no success, getting this response:
{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content:....}
Any ideas what i should do? I succeeded using Powershell-script, but I need to do this in my C# app.
Thank you for your response Fei Xue, i believe i had the right permissions. What i did to solvem my problem.
First off i removed my own custom class "NewUser", then i downloaded this sample-project: https://github.com/AzureADQuickStarts/B2C-GraphAPI-DotNet/blob/master/B2CGraphClient/B2CGraphClient.cs to eliminate the risk that my code was wrong. I modified it to support my needs, then i created a simple JObject:
var jsonObject = new JObject
{
{"accountEnabled", true},
{"country", customer.CustomerBase.Company},
{"creationType", "LocalAccount"},
{"displayName", pendingCustomer.Email.Trim()},
{"passwordPolicies", "DisablePasswordExpiration,DisableStrongPassword"},
{"passwordProfile", new JObject
{
{"password", pwd},
{"forceChangePasswordNextLogin", true}
} },
{"signInNames", new JArray
{
new JObject
{
{"value", pendingCustomer.Email.Trim()},
{"type", "emailAddress"}
}
}
}
};
client = new B2CGraphClient(ClientId, ClientSecret, TenantId);
var response = await client.CreateUser(jsonObject.ToString());
var newUser = JsonConvert.DeserializeObject<User>(response);
From B2CGraphClient.cs
private async Task<string> SendGraphPostRequest(string api, string json)
{
// NOTE: This client uses ADAL v2, not ADAL v4
var result = authContext.AcquireToken(Globals.aadGraphResourceId, credential);
var http = new HttpClient();
var url = Globals.aadGraphEndpoint + tenant + api + "?" + Globals.aadGraphVersion;
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
var formatted = JsonConvert.DeserializeObject(error);
//Console.WriteLine("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
Logger.Error("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
}
Logger.Info((int)response.StatusCode + ": " + response.ReasonPhrase);
return await response.Content.ReadAsStringAsync();
}
This finally solved all my problems, it was probably an format-error in the serialization of my NewCustomer-class, which then got rejected by the API.
Did you grant the app sufficient permission to operate users? The create user REST API works well for me for the B2C tenant.
Here are the steps I tested:
1.Create the app via the PowerShell below
PowerShell:
$bytes = New-Object Byte[] 32
$rand = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rand.GetBytes($bytes)
$rand.Dispose()
$newClientSecret = [System.Convert]::ToBase64String($bytes)
New-MsolServicePrincipal -DisplayName "My New B2C Graph API App" -Type password -Value
2.Grant the app to User Account Administrator role.
Add-MsolRoleMember -RoleObjectId fe930be7-5e62-47db-91af-98c3a49a38b1 -RoleMemberObjectId 7311370c-dac3-4f34-b2ce-b22c2a5a811e -RoleMemberType servicePrincipal
3.Get the token for the app with client credential flow
POST: https://login.microsoftonline.com/adb2cfei.onmicrosoft.com/oauth2/token
grant_type=client_credentials&client_id={AppPrincipalId return by PowerShell}&client_secret={client_secret}&resource=https%3A%2F%2Fgraph.windows.net
4.Create the user with REST below:
POST: https://graph.windows.net/adb2cfei.onmicrosoft.com/users?api-version=1.6
authorization: bearer {token}
content-type: application/json
{
"accountEnabled": true,
"creationType": "LocalAccount",
"displayName": "Alex Wu",
"passwordProfile": {
"password": "Test1234",
"forceChangePasswordNextLogin": false
},
"signInNames": [
{
"type": "userName",
"value": "AlexW"
},
{
"type": "emailAddress",
"value": "AlexW#example.com"
}
]
}
I'm trying to make a simple request to the Basecamp API, I'm following the instructions provided adding in a sample user agent and my credentials yet I keep getting a 403 Forbidden response back.
My credentials are definitely correct so is it a case of my request/credentials being set incorrectly?
This is what I have (removed personal info):
var httpClient = new HttpClient();
var content = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("User-Agent", "MyApp [EMAIL ADDRESS]") });
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(string.Format("{0}:{1}", "[USERNAME]", "[PASSWORD]"))));
var response = await httpClient.PostAsync("https://basecamp.com/[USER ID]/api/v1/projects.json", content);
var responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
Console.WriteLine(await reader.ReadToEndAsync());
}
A quick look over their documentation seems to indicate that the projects.json endpoint accepts the following in the body of the POST:
{
"name": "This is my new project!",
"description": "It's going to run real smooth"
}
You're sending the User-Agent as the POST body. I'd suggest you change your code as follows:
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "[USERNAME]", "[PASSWORD]")));
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Add("User-Agent", "MyApp [EMAIL ADDRESS]");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
var response = await httpClient.PostAsJsonAsync(
"https://basecamp.com/[USER ID]/api/v1/projects.json",
new {
name = "My Project",
description = "My Project Description"
});
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}
This posts the payload as specified in the docs and sets your user agent in the headers as it should be.