I can accomplish all other tasks with the rest API, like uploading and downloading files, navigating through the file directory. I just keep getting either 400 Bad Request or sometimes with some tries I'll get 500 Internal Server Error. Also, I can create the request on postman and its successful
this is what the request should look like the rest is me creating it in c#
POST https://{site_url}/_api/web/folders
Authorization: "Bearer " + accessToken
Accept: "application/json;odata=verbose"
Content-Type: "application/json"
Content-Length: {length of request body as integer}
X-RequestDigest: "{form_digest_value}"
{
"__metadata": {
"type": "SP.Folder"
},
"ServerRelativeUrl": "/document library relative url/folder name"
}
private async Task PostFolderSharePoint(string url, string serverRelativeUrl)
{
string accessToken = GetAccessToken().GetAwaiter().GetResult();
string jsoncontent = JsonConvert.SerializeObject("{\"__metadata\": {\"type\": \"SP.Folder\"},\"ServerRelativeUrl\": serverRelativeUrl}");
var content = new StringContent(jsoncontent, Encoding.UTF8, "application/json");
var FormDiGestValue = await GetFormDigestValue(accessToken);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var requestMessage = new HttpRequestMessage(HttpMethod.Post,url) { Content = content };
requestMessage.Headers.Add("X-RequestDigest", FormDiGestValue);
HttpResponseMessage response = await _httpClient.SendAsync(requestMessage).ConfigureAwait(false);
return response;
}
This is how I create a folder with the Sharepoint REST API:
public async Task<string> CreateFolder(string folderName, string relativeUrl)
{
try
{
var url = "https://your.sharepoint.com/sites/devsite/_api/web/folders";
var json = "{\"ServerRelativeUrl\": \"" + relativeUrl + "/" + folderName + "\"}";
var payload = new StringContent(json, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("accept", "application/json;odata=verbose");
client.DefaultRequestHeaders.Add("X-User-Agent", "spoc");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var response = await client.PostAsync(url, payload);
return await response.Content.ReadAsStringAsync();
}
catch (WebException we)
{
throw new SomethingException(we);
}
}
and to use it:
var modFolder = await spocRest.CreateFolder("MOD1", "Shared Documents");
Related
We have an API that utilizes a service account (work account type - not a personal account) to do the following:
Using our Service Account, Gets a Token from our Azure AD with scopes: ["user.read", "User.Read.All", "Files.ReadWrite.All", "ChatMessage.Send", "Chat.Create", "Chat.ReadWrite"]
Use that token to upload a file to our SharePoint. -> This succeeds
Use that token to Get the UserID from email (UserPrincipalNames map in our AD, so this is not a concern) -> This succeeds
Use that token to Create a new chat/Get the existing chat between the user & our service account (using POST /v1.0/chats) -> This returns 401 Unauthorized
Send the message from service account to user (using POST /v1.0/chats/{chatID returned from step 4}/messages)
The users we are attemping to send these messages to are all in our Azure AD.
We are unsure how the previous requests with this token succeed, and the Create/Get Chat fails with a 401. We have confirmed that the token is correctly being set in the authorization header (we are using the exact same process as the previous requests).
Also, we have these API Permissions set in our Azure AD for this application:
If we use jwt.io to examine the token, we do see the scope is set in the token being set in the Authorization header of the request.
Additionally the audience is set to Graph API:
Here is our code:
using Microsoft.Graph;
using Newtonsoft.Json;
using OurAPI.Helpers.IHelpers;
using OurAPI.Models;
using OurAPI.Repositories.IRepositories;
using System.Text;
namespace OurAPI.Repositories
{
public class TeamsRepository : ITeamsRepository
{
private readonly IConfiguration _config;
private readonly ITokenHelper _tokenHelper;
private readonly IHttpClientFactory _httpClientFactory;
public TeamsRepository(IConfiguration config, ITokenHelper tokenHelper, IHttpClientFactory httpClientFactory)
{
_config = config;
_tokenHelper = tokenHelper;
_httpClientFactory = httpClientFactory;
}
public async Task<object> GeneratePDFAndSendToTeams(TeamsPostRequest request)
{
// Authenticate
string token = await _tokenHelper.GetMicrosoftGraphAccessToken();
// Convert from Base64 to Memory Stream
var file = GeneratePDF(request.Base64);
// Upload PDF to SharePoint
var sharepointFile = await UploadFile(file, request, token);
// Get UserID from email
var user = await GetUser(request.User, token);
// Create a new chat with service account or Retrieve Chat if already exists
var chat = await GetChat(user.Id, token);
// Post to chat between service account and requesting user
var chatMessage = await SendToTeams(sharepointFile, chat, token);
return chat;
}
public async Task<object> GetChats(string token)
{
using var request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/users/serviceaccount#domain.com/chats");
request.Headers.Add("authorization", "Bearer " + token);
request.Headers.Add("accept", "application/json");
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contents = await response.Content.ReadAsStringAsync();
var chats = JsonConvert.DeserializeObject(contents);
return chats;
}
public async Task<User> GetUser(string userEmail, string token)
{
using var request = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/users/" + userEmail);
request.Headers.Add("authorization", "Bearer " + token);
request.Headers.Add("accept", "application/json");
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contents = await response.Content.ReadAsStringAsync();
var user = JsonConvert.DeserializeObject<User>(contents);
return user;
}
public async Task<Chat> GetChat(string userID, string token)
{
var chatRequest = new Models.ChatRequest(userID);
chatRequest.ChatType = "oneOnOne";
var chatMember = new ChatMember();
chatMember.Type = "#microsoft.graph.aadUserConversationMember";
chatMember.Roles = new List<string>() { "owner" };
chatMember.User = $"https://graph.microsoft.com/beta/users('{userID}')";
var serviceAccount = new ChatMember();
serviceAccount.Type = "#microsoft.graph.aadUserConversationMember";
serviceAccount.Roles = new List<string>() { "owner" };
serviceAccount.User = "https://graph.microsoft.com/beta/users('{OurServiceAccountID}')";
chatRequest.Members = new List<ChatMember> { chatMember, serviceAccount };
using var request = new HttpRequestMessage(HttpMethod.Post, "https://graph.microsoft.com/v1.0/chats");
request.Headers.Add("authorization", "Bearer " + token);
request.Headers.Add("accept", "application/json");
string content = JsonConvert.SerializeObject(chatRequest);
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contents = await response.Content.ReadAsStringAsync();
var chat = JsonConvert.DeserializeObject<Chat>(contents);
return chat;
}
// POST /chats/{chat-id}/messages
public async Task<ChatMessage> SendToTeams(DriveItem sharePointFile, Chat chat, string token)
{
var chatMessageRequest = new Models.ChatMessageRequest(sharePointFile);
using var request = new HttpRequestMessage(HttpMethod.Post, "https://graph.microsoft.com/v1.0/chats/" + chat.Id + "/messages");
request.Headers.Add("authorization", "Bearer " + token);
request.Headers.Add("accept", "application/json");
request.Content = new StringContent(JsonConvert.SerializeObject(chatMessageRequest), Encoding.UTF8, "application/json");
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(request);
//response.EnsureSuccessStatusCode();
var contents = await response.Content.ReadAsStringAsync();
var chatMessageResponse = JsonConvert.DeserializeObject<ChatMessage>(contents);
return chatMessageResponse;
}
public async Task<DriveItem> UploadFile(MemoryStream file, TeamsPostRequest teamsPostRequest, string token)
{
string siteID = "{ourSiteID}";
string PTparentID = "{ourParentID}"
string custNameForFile = teamsPostRequest.CustomerName;
using var request = new HttpRequestMessage(HttpMethod.Put, _config["Graph:BaseUrl"] + "/sites/" + siteID + "/drive/items/" + PTparentID + ":/" + custNameForFile + teamsPostRequest.PickTicketNo + ".pdf:/content");
request.Headers.Add("authorization", "Bearer " + token);
request.Headers.Add("accept", "application/json");
request.Content = new StreamContent(file);
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var contents = await response.Content.ReadAsStringAsync();
var driveItem = JsonConvert.DeserializeObject<DriveItem>(contents);
return driveItem;
}
private static MemoryStream GeneratePDF(string base64)
{
byte[] bytes = Convert.FromBase64String(base64);
MemoryStream ms = new(bytes);
return ms;
}
}
}
Here is the request we are making to get the token:
public async Task<string> GetMicrosoftGraphAccessToken()
{
string authority = "https://login.microsoftonline.com/{ourTenantID}/";
string[] scopes = new string[] { "user.read", "User.Read.All", "Files.ReadWrite.All", "ChatMessage.Send", "Chat.Create", "Chat.ReadWrite" };
IPublicClientApplication app = PublicClientApplicationBuilder.Create(_config["AzureAD:ClientId"])
.WithAuthority(authority)
.Build();
var securePassword = new SecureString();
foreach (char c in _config["MicrosoftGraph:Password"])
{
securePassword.AppendChar(c);
}
AuthenticationResult result = await app.AcquireTokenByUsernamePassword(scopes, _config["MicrosoftGraph:Username"], securePassword)
.ExecuteAsync();
return result.AccessToken;
}
We are at a lose for what could be going on here. Any ideas would be greatly appreciated!
It helps to see the details of the token.
Copy the token, paste it at https://jwt.ms and inspect the details.
You’re probably interested in the scopes.
I guess the account you’re using should be one of the participants of the chat, this cannot be used to create chats between other users.
https://learn.microsoft.com/en-us/graph/api/chat-post you seem to be doing the right request.
I have created a simple console app in C#, I need to request access token without using SDK. I have managed to launch a URL to request code. I get code but trying to call the access_token endpoint is a challenge. I need help on how I can get access_token and refresh_token. Attached is the screenshot of codes having all the request details and the endpoint I used as follows.
Endpoint used: https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer
Parameters: code,=[codeReceived] grant_type = authorization_code and redirect_uri = [RedirectUrl]
Headers:Authorization: Basic [Base64EncodedBytes], Accept: application/json, Host: oauth.platform.intuit.com, Content-Type: application/x-www-form-urlencoded
I have created a simple console app in C#, I need to request access token without using SDK. I have managed to launch a URL to request code. I get code but trying to call the access_token endpoint is a challenge. I need help on how I can get access_token and refresh_token. Attached is the screenshot of codes having all the request details and the endpoint I used as follows.
Posting
Endpoint used: https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer
Parameters:[enter image description here][1]
code,=[codeReceived] grant_type = authorization_code and redirect_uri = [RedirectUrl]
Headers:
Authorization: Basic [Base64EncodedBytes], Accept: application/json, Host: oauth.platform.intuit.com, Content-Type: application/x-www-form-urlencoded
This is the Client Class I've created:
public class RestClient
{
public string ClientID;
public string ClientSecret;
public string RedirectUrl = "https://devices.pythonanywhere.com/";
public string Environment = "sandbox";
private async Task<string> GetAccessTokenAsync(string Url, string code, string ClientId, string ClientSecret)
{
var stringBytes = Encoding.UTF8.GetBytes($"{ClientId}:{ClientSecret}");
var encodedBytes = Convert.ToBase64String(stringBytes);
var uriBuilder = new UriBuilder(Url);
var query = HttpUtility.ParseQueryString(uriBuilder.Query);
query["grant_type"] = "authorization_code";
query["code"] = $"{code}";
query["redirect_uri"] = $"{RedirectUrl}";
uriBuilder.Query = query.ToString();
Url = uriBuilder.ToString();
var DecodedUrl = HttpUtility.UrlDecode(Url);
Console.WriteLine(encodedBytes);
HttpRequestMessage request = new(HttpMethod.Post, DecodedUrl);
request.Headers.Add("Accept", "application/json");
request.Headers.Add("Authorization", $"Basic {encodedBytes}");
request.Headers.Add("Host", "oauth.platform.intuit.com");
request.Content = new StringContent("application/x-www-form-urlencoded");
using HttpClient client = new();
using HttpResponseMessage response = await client.SendAsync(request);
var body = response.Content.ReadAsStringAsync();
return body.Result;
}
public string GetTokens(string Url, string code, string ClientId, string ClientSecret)
{
try
{
var response = GetAccessTokenAsync(Url, code, ClientId, ClientSecret).Result;
if (response.Length>0)
{
return "There is data";
}
return "No data";
}
catch (Exception ex)
{
return ex.Message;
}
}
}
and this here is where I'm calling it
class Program
{
static void Main(string[] args)
{
var client = new RestClient();
client.ClientID = "AB8EMz5arbI**************************************";
client.ClientSecret = "4y4vsz*********************************";
var OauthUrl = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
var code = "AB11644908535RgJ**************************";
Console.WriteLine($"Response: {client.GetTokens(OauthUrl, code, client.ClientID, client.ClientSecret)}");
}
}
I was making a mistake in my C# code. Here is the working code that I used in GetAccessTokenAsync:
private async Task<string> GetAccessTokenAsync(string Url, string code, string ClientId, string ClientSecret)
{
var stringBytes = Encoding.UTF8.GetBytes($"{ClientId}:{ClientSecret}");
var encodedBytes = Convert.ToBase64String(stringBytes);
HttpRequestMessage request = new(HttpMethod.Post, Url);
request.Headers.TryAddWithoutValidation("Accept", "application/json");
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {encodedBytes}");
var contentList = new List<string>();
contentList.Add("grant_type=authorization_code");
contentList.Add($"code={code}");
contentList.Add($"redirect_uri={RedirectUrl}");
request.Content = new StringContent(string.Join("&", contentList));
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
using HttpClient client = new();
using HttpResponseMessage response = await client.SendAsync(request);
var body = response.Content.ReadAsStringAsync();
return body.Result;
}
I hate reviving old threads, but your answer helped me a lot. I had to change it a little bit to accept the refresh token rather than authorization code and thought I would post it here. I banged my head around for quite some time trying to figure this out without any useful documentation that I could find on the matter. I hope it helps someone in the same way that your code has helped me. Thanks!
public async Task<string> RefreshAccessToken(string Url, string RefreshToken, string ClientId, string ClientSecret)
{
var stringBytes = Encoding.UTF8.GetBytes($"{ClientID}:{ClientSecret}");
var encodedBytes = Convert.ToBase64String(stringBytes);
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, Url);
request.Headers.TryAddWithoutValidation("Accept", "application/json");
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {encodedBytes}");
var contentList = new List<string>();
contentList.Add("grant_type=refresh_token");
contentList.Add($"refresh_token={RefreshToken}");
request.Content = new StringContent(string.Join("&", contentList));
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.SendAsync(request))
{
var body = response.Content.ReadAsStringAsync();
return body.Result;
}
}
}
Alternatively, I find that something like this works too. Using RestSharp..
public string RefreshAccessToken()
{
try
{
var stringBytes = Encoding.UTF8.GetBytes($"{strClientID}:{strClientSecret}");
var encodedBytes = Convert.ToBase64String(stringBytes);
var client = new RestClient("https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer");
client.UseJson();
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", $"Basic {encodedBytes}");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "refresh_token");
request.AddParameter("refresh_token", CurrentRefreshToken);
IRestResponse response = client.Execute(request);
return response.Content;
}
catch (Exception ex)
{
WriteError("RefreshAccessToken() - " + ex.Message);
return ex.Message;
}
}
I'm trying to make HTTP request with Bearer authorization. I have a token, token is valid. Tried to do it 3 different ways: App, that request must be implemented in, POSTMAN, console app with a code generated with POSTMAN (C# - RestSharp) from the same POSTMAN call:
App POST method:
public async Task<TResponse> Post<TRequest, TResponse>(string requestUri, TRequest data)
{
LogInit(requestUri, HttpMethod.Post, data);
using (var request = new HttpRequestMessage(HttpMethod.Post, requestUri))
{
var token = await GetToken(_httpClient);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
request.Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
using (var response = await _httpClient.SendAsync(request))
{
if (!response.IsSuccessStatusCode)
{
throw await HandleErrorResponse(response);
}
var responseObj = await response.Content.ReadAsJsonAsync<TResponse>();
return responseObj;
}
}
}
Console POST method:
static void Main(string[] args)
{
var client = new RestClient("http://***");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer xxx");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Cookie", "ARRAffinity=xxx");
var body = #"{
" + "\n" +
#" ""amisPersonId"": ***,
" + "\n" +
#" ""name"": ""***"",
" + "\n" +
#" ""surname"": ""***"",
" + "\n" +
#" ""personalCode"": ""***"",
" + "\n" +
#" ""email"": ""***"",
" + "\n" +
#" ""phoneNumber"": ""***""
" + "\n" +
#"}";
request.AddParameter("application/json", body, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
Requests tracked with debugger:
App request
Console app request
POSTMAN request
POSTMAN gets 200/400 reponses, App and Console app gets 401 (Unauthorized). BOTH Apps are .NET CORE apps.
assuming that you have correct token.AccessToken ,try to replace
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
with
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.AccessToken);
I am attempting to consume a Data source from Plex a cloud ERP System with Rest. I am receiving a forbidden status code upon sending the PUT
public static string Put(string url,string Body,PCNModel pcn)
{
HttpClient client = new HttpClient();
int timeOutSec = 90;
string accept = "application/json";
string acceptEncoding = "gzip, deflate";
string contentType = "application/json";
var credentials = pcn.UserName + ":" + pcn.Password;
var bytes = Encoding.UTF8.GetBytes(credentials);
var encodedCredentials = Convert.ToBase64String(bytes);
var authorizationHeaderValue = encodedCredentials;
HttpResponseMessage response = new HttpResponseMessage();
client.Timeout = new TimeSpan(0, 0, timeOutSec);
//client.DefaultRequestHeaders.Add("Accept", string.Format(accept));
client.DefaultRequestHeaders.Add("Accept", (accept));
client.DefaultRequestHeaders.Add("Accept-Encoding", string.Format(acceptEncoding));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
client.DefaultRequestHeaders.Add("Authorization", string.Format("Basic {0}", authorizationHeaderValue));
HttpContent httpBody = Body;
httpBody.Headers.ContentType = new MediaTypeHeaderValue(contentType);
response = client.PutAsync(url, httpBody).Result;
var error = response.StatusCode.ToString();
var requestMessage = response.RequestMessage;
var responseContent = response.Content;
var responseReasonPhrase = response.ReasonPhrase;
var responseHeader = response.Headers;
MessageBox.Show(error);
MessageBox.Show(requestMessage.ToString());
//MessageBox.Show(responseContent.ToString());
//MessageBox.Show(responseReasonPhrase.ToString());
//MessageBox.Show(responseHeader.ToString());
var content = response.Content.ReadAsStringAsync().Result;
return content;
}
I am not sure where it is bouncing back at me.
You need to parse body to json before calling PutAsync here is a small code sinppet
client.DefaultRequestHeaders.Add("authKey", authKey);
var json = JsonConvert.SerializeObject(product, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PutAsync(url, content);
if (response.IsSuccessStatusCode)
{
}
else
{
var result = response.Content.ReadAsStringAsync().Result;
throw new Exception("Error Occured in Update Product" + result);
}
It turns out that the credentials I was provided were incorrect. Which prevented me from processing web services calls to the endpoint.
UPDATE 1
I think I am using incorrect URL, this doc says to use "https://www.googleapis.com/drive/v2/files" & this doc says to use "https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart". Though I am getting same 400 bad request.
Can I use Google Drive upload REST API in background uploader class?
I am following this doc from Google Drive to upload files but I am getting 400 - Bad request. What's wrong with my code?
public static async Task UploadFileAsync(Token AuthToken, StorageFile file, DriveFile objFolder)
{
try
{
if (!httpClient.DefaultRequestHeaders.Contains("Authorization"))
{
httpClient.DefaultRequestHeaders.Add("Authorization", AuthToken.TokenType + " " + AuthToken.AccessToken);
}
var JsonMessage = JsonConvert.SerializeObject(objFolder);
/*JsonMessage = {"title":"c4611_sample_explain.pdf","mimeType":"application/pdf","parents":[{"id":"root","kind":"drive#fileLink"}]}*/
var JsonReqMsg = new StringContent(JsonMessage, Encoding.UTF8, "application/json");
var fileBytes = await file.ToBytesAsync();
var form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(fileBytes));
form.Add(JsonReqMsg);
form.Headers.ContentType = new MediaTypeHeaderValue("multipart/related");
var UploadReq = await httpClient.PostAsync(new Uri("https://www.googleapis.com/drive/v2/files?uploadType=multipart"), form);
if (UploadReq.IsSuccessStatusCode)
{
var UploadRes = await UploadReq.Content.ReadAsStringAsync();
}
else
{
}
}
catch (Exception ex)
{
}
}
You must use https://www.googleapis.com/upload/drive/v2/files
I have a working sample here (sorry, the JSON string is hard coded):
// Multipart file upload
HttpClient client = new HttpClient();
string uriString = "https://www.googleapis.com/upload/drive/v2/files?key=<your-key>&access_token=<access-token>&uploadType=multipart";
Uri uri = new Uri(uriString);
HttpContent metadataPart = new StringContent(
"{ \"title\" : \"My File\"}",
Encoding.UTF8,
"application/json");
HttpContent mediaPart = new StringContent(
"The naughty bunny ate all the cookies.",
Encoding.UTF8,
"text/plain");
MultipartContent multipartContent = new MultipartContent();
multipartContent.Add(metadataPart);
multipartContent.Add(mediaPart);
HttpResponseMessage response = await client.PostAsync(uri, multipartContent);
string responseString = await response.Content.ReadAsStringAsync();