How to implement OAuth2.0 using client credentials grant-type in a way that it supports Json raw body with token request in c# - oauth-2.0

My project is a web api project which is using owin for generating token after authentication. it is built using asp.net framework.
It currently accepts token request in below format -
var client = new RestClient("http://localhost:63202/1.0/token");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", "12345667");
request.AddParameter("client_secret", "secret");
I want my API to support Json raw body instead of URL encoded one with the token request as below -
var client = new RestClient("http://localhost:63202/1.0/token");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
var body = #"{" + "\n" +
#" "grant_type": "client_credentials"," + "\n" +#" "client_id": "1234567890""," + "\n" +#"client_secret": "channelsintegration123456789012345" + "\n" +
#"}"
request.AddParameter("application/json", body, ParameterType.RequestBody);
Issue - When the request is made and ValidateClientAuthentication() method is hit, the context doesn't have client id and client secret when I make the above (#2) request.

Related

Graph API not allowing online meetings

I am currently setting up a web page where users can send event requests to others using the Microsoft Graph api. I would like users to be able to send an online meeting request and then provide the options of ms teams and Skype.
However as soon as I add the property 'isOnlineMeeting' and/or 'onlineMeetingProvider' I will always return an error 400 with a bad request. This is because the property doesn't exist on the /me/events.
(the response)
I have no idea why however, currently I am using the microsoft graph explorer to test the request.
I have made sure that every permission is needed to send an invite:
Calendar.Read
Calendar.Read.Shared
Calendar.ReadWrite
Calendar.ReadWrite.Shared
If a meeting is sent without these properties it works fine. I have created other personal outlook accounts and it works as expected with this property. I have asked other people in my org to try too and theirs works fine.
Does this mean that my ms account is broken in some way? if so how could I fix it in order to send this request.
Try this:
var body= "{email body};
var string = "{\"subject\": \"Join the Teams Meeting\", \"body\": {\"contentType\": \"HTML\", \"content\": \"" + body + "\" }, \"start\": {\"dateTime\": \"2020-09-28T19:30:34\",\"timeZone\": \"Pacific Standard Time\" }, \"end\": { \"dateTime\": \"2020-09-28T20:00:34\", \"timeZone\": \"Pacific Standard Time\"}, \"location\":{ \"displayName\":\"Team meeting\" }, \"attendees\": [ { \"emailAddress\": { \"address\":\"xxxx#in.xxx.com\", \"name\": \"xxxx xxxx\" }, \"type\": \"required\" } ],\"allowNewTimeProposals\": \"true\"}";
client = new RestClient("https://graph.microsoft.com/v1.0/me/events");
request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/json");
request.AddHeader("authorization", "Bearer " + token);
request.AddHeader("accept-language", "en");
request.AddHeader("accept", "application/json");
request.AddParameter("application/json", string, ParameterType.RequestBody);
response = client.Execute(request);
To generate token:
var client = new RestClient("https://login.microsoftonline.com/{tenant-Id}/oauth2/v2.0/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddHeader("grant_type", "password");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=password&client_id={client-Id}&client_secret={client-secret}&scope={scopeurl}&userName={username}&password={password}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
var json = response.Content;
var JSONObject = JObject.Parse(json);
var token = (string)JSONObject["access_token"];

Set url for GraphApi B2C login

I need to query the Graph API to get the username in the claims.
I've implemented something based on what I've found on the net, but I keep getting 403 Forbidden, from Graph API.
Can anyone help me with this?
This is my code:
var clientId = "clientId";
var clientSecret = "clienSecret";
var tenant = "tenantName";
var userObjectId = claimsPrincipal.Claims.Where(i => i.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier").FirstOrDefault().Value;
var aadGraphVersion = "api-version=1.6";
var query = "/users/" + userObjectId;
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/" + tenant);
// The ClientCredential is where you pass in your client_id and client_secret, which are
// provided to Azure AD in order to receive an access_token using the app's identity.
ClientCredential credential = new ClientCredential(clientId, clientSecret);
// First, use ADAL to acquire a token using the app's identity (the credential)
// The first parameter is the resource we want an access_token for; in this case, the Graph API.
AuthenticationResult result = await authContext.AcquireTokenAsync("https://graph.windows.net", credential);
// For B2C user management, be sure to use the Azure AD Graph API for now.
HttpClient http = new HttpClient();
//var url = "https://graph.windows.net/" + tenant + "/users/" + userObjectId + "/?api-version=1.6";
//var url = graphResource + "tenant" + "/users/" + userObjectId + "/?api-version=1.6";
string url = "https://graph.windows.net/" + tenant + "/users/" + userObjectId + "?" + aadGraphVersion;
//url += "&" + query;
// Append the access token for the Graph API to the Authorization header of the request, using the Bearer scheme.
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
HttpResponseMessage response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
string error = await response.Content.ReadAsStringAsync();
object formatted = JsonConvert.DeserializeObject(error);
throw new WebException("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
}
I think I have a problem with the URL that is not set correctly. The token is correct, I got it ok with the credentials.
I do think it is an issue with the URL. You are getting this error as you have provided user read permissions to your registered application. Please make sure that -
You go to Application registrations menu on your tenant
Select "Required Permissions" menu and click on Windows Azure Active Directory
In the "Enable Access" menu select "Read Directory Data" permissions under Application Permissions section and click save.
Once saved on "Required Permissions" menu click on "Grant Permissions" button to provide the consent.
You may need to select other options like "Read and Write Directory Data" if you wish to provide your application to create/update/delete users.

Spring Security and Angular 5

Right now I'm sending username and password through header from my angular 5 app after successful login to access spring rest api. After Successful I'm getting unique sessionId from spring in response can I use that ID instead of credentials to authenticate
angular code
let d=localStorage.getItem('currentUser');
let headers = new Headers();
var user=JSON.parse(d);
headers.append('Accept', 'application/json');
// creating base64 encoded String from user name and password
var base64Credential: string = btoa(user.principal.username+ ':' + user.principal.password);
headers.append("Authorization", "Basic " + base64Credential);
let options = new RequestOptions({ headers: headers
});
var self = this;
self.greeting = {id:'', content:''};
http.get(this.url,options).map(response => self.greeting = response.json);
You can use jwt token for this.
Store the sessionId in localStorage or a cookie.
Send it inside the request header in each and every request (use httpInteceptor for this)
https://medium.com/#ryanchenkie_40935/angular-authentication-using-the-http-client-and-http-interceptors-2f9d1540eb8
In the Java application, add filter to all the requests, which need to be protected.

Bad request 400 when exchanging refresh_token for access_token with box.com

I have successfully done this in the past for other services, however with box.com I get an error and I've tried everything I could think off and that others have suggested here.
I'm using .NET C#;
string postdata = "";
postdata += "client_id=" + HttpUtility.UrlEncode(client_id) + "&";
postdata += "client_secret=" + HttpUtility.UrlEncode(client_secret) + "&";
postdata += "refresh_token=" + HttpUtility.UrlEncode(refreshToken) + "&";
postdata += "redirect_uri=" + HttpUtility.UrlEncode(_redirectUri) + "&";
postdata += "grant_type=refresh_token";
var json = PostResponse(new Uri(#"https://www.box.com/api/oauth2/token"), postdata);
I've tried both with and without urlencoding of the values. Normally urlencoding is not needed in my experience.
I've also tried different order of parameters.
private string PostResponse(Uri uri, string postdata)
{
var bytes = Encoding.UTF8.GetBytes(postdata);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.ContentType = "application/x-www-form-urlencoded; charset=utf-8";
request.ContentLength = bytes.Length;
Stream OutputStream = request.GetRequestStream();
OutputStream.Write(bytes, 0, bytes.Length);
var response = request.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}
This code fails with error 400 (bad request). Similar code works fine with for example Google Drive.
Can anyone spot what I'm doing wrong with box.com? Thanks!
Got it working using box_device_id and box_device_name (indirectly part of my problem) plus examining the response in details which showed that a json error message was returned stating that the refresh token had expired. Turns out that Box expires refresh tokens when using them, issuing a new one. This is different from the other cloud drives I've integrated with.

Connecting to Twitter - RestSharp OAuth2

I am attempting to connect to the Twitter API with these instructions
https://dev.twitter.com/docs/auth/application-only-auth
Here is my code:
var baseUrl = "http://api.twitter.com/";
var client = new RestClient(baseUrl);
var request = new RestRequest("/oauth2/token", Method.POST);
var concat = ConfigurationManager.AppSettings["TwitterConsumerKey"] + ":" +
ConfigurationManager.AppSettings["TwitterConsumerSecret"];
string encodeTo64 = concat.EncodeTo64();
request.AddHeader("Authorization", "Basic " + encodeTo64);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
request.AddBody("grant_type=client_credentials");
IRestResponse restResponse = client.Execute(request);
EncodeTo64
static public string EncodeTo64(this string toEncode)
{
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
string returnValue
= System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
Response.Content is the following
"{\"errors\":[{\"code\":170,\"label\":\"forbidden_missing_parameter\",\"message\":\"Missing required parameter: grant_type\"}]}"
Is this part wrong?
request.AddBody("grant_type=client_credentials");
I have verified that my credentials are correct (I got that error before, but resolved it, so it should be OK).
The instructions on the Twitter page confused me. "The body of the request must be grant_type=client_credentials."
As for Restsharp, it's not AddBody, but AddParameter.
So:
request.AddParameter("grant_type", "client_credentials");

Resources