401 (Unauthorized) when trying to access REST API - c#

So basically, I am trying to connect to a REST API online. Easy enough right?
However I am getting a 401 (Unauthorized) error whenever I try to connect. I am using a C# console app to test this, and I have also tried using PUTMAN (Google Chrome App to view HTTP Requests).
Here is the link to the API I am using: https://community.dynatrace.com/community/display/APMSAASDOC/Login+-+REST+API
I follow all the steps listed. I know my username and password is correct (have logged into the Dynatrace Portal). Does anyone have any ideas what could be wrong? Here is my code below (I have removed the actual username and password for obvious reasons):
static async Task RunAsync()
{
string _user;
string _password;
string _authorizationType;
string _contentType;
string _CredentialsToBase64;
string _url = "https://datafeed-api.dynatrace.com";
_user = "MYUSERNAME";
_password = "MYPASSWORD";
_authorizationType = "basic";
_contentType = "application/json";
_CredentialsToBase64 = System.Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes(_user + ":" + _password));
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(_contentType));
client.DefaultRequestHeaders.Add("Authorization", _authorizationType + " " + _CredentialsToBase64);
using (HttpResponseMessage httpResponse = await client.GetAsync("publicapi/rest/v1.0/login?user=MYUSERNAME&password=MYPASSWORD HTTP/1.1"))
{
if (httpResponse.IsSuccessStatusCode)
{
Console.WriteLine("Success");
}
else
{
Console.WriteLine(string.Format("Service request failed ({0})", httpResponse.StatusCode));
}
}
}

The HTTP/1.1 string at the end of the client.GetAsync method call is probably being translated into password=MYPASSWORD%20HTTP/1.1 (or similar) which results in the error. Try removing that, and see if it works.
Note: %20 is a urlencoded space
Another Option The answer to this post might be related. To summarize, it appears that formatting a request requires the BaseAddress to have a trailing slash and the GetAsync string to not start with a slash.

Sorry for the headache everyone. The problem was an account issue with the company itself. I contacted them and they noticed the problem was with a migration of accounts from a old to new portal. So there was nothing wrong with our end. Thanks for your help everyone!

Remove " HTTP/1.1" from the end of your GET url, its being added to the end of your password, hence the 401

Related

How do I fix the Problem Error 404 from Webclient

Hey guys,
I have a problem with my code. Since about a week my code is not working anymore without any changes. I am pretty sure, that my could should work. All I get is Error 404: forbidden.
Below is a snippet of my Code. I also read about adding a header of the webclient, which did not help. Any other suggestions? I am sorry if my syntax is not that good, it is my first post on stackoverflow.
Thanks in advance!
string epicId = "ManuelNotManni";
WebClient webClient = new WebClient();
Uri uri = new Uri("https://api.tracker.gg/api/v2/rocket-league/standard/profile/epic/");
string result = String.Empty;
try
{
string website = $"{uri.ToString()}{epicId}?";
result = webClient.DownloadString(website);
}
catch (Exception ex)
{
Console.WriteLine($"Error:\n{ex}");
Console.ReadLine();
}
finally
{
webClient.Dispose();
}
This is the exact error:
System.Net.WebException: The remote server returned an error: (403) Forbidden.
at System.Net.HttpWebRequest.GetResponse()
at System.Net.WebClient.GetWebResponse(WebRequest request)
at System.Net.WebClient.DownloadBits(WebRequest request, Stream writeStream)
at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest& request)
at System.Net.WebClient.DownloadString(Uri address)
at System.Net.WebClient.DownloadString(String address)
at TestProject.Program.Main(String[] args) in > C:\Users\Manue\source\repos\TestProject\Program.cs:line 17
You're right. Your code should work fine.
Issue is that URL you're requesting which is actually:
https://api.tracker.gg/api/v2/rocket-league/standard/profile/epic/ManuelNotManni?
This returns a 403 status code in any case - no matter if you use a browser, your code or for example postman.
I suggest to have a look at the response body while using postman.
It shows this
<html class="no-js" lang="en-US">
<!--<![endif]-->
<head>
<title>Attention Required! | Cloudflare</title>
<meta name="captcha-bypass" id="captcha-bypass" />
Tracker.gg wants API users to register their apps with them before they're given access to the API.
What you need to do is to first head to their Getting Started page. Here you will have to create an app, which should give you an authentication key.
When you have done this, you want to change your code slightly to add the Authentication Header. Like so for example:
var webClient = new WebClient();
webclient.Headers.Add("TRN-Api-Key", "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
As a sidenote, WebClient has been deprecated and it's recommended to use HttpClient from now on. Here's your code with HttpClient instead:
var epicId = "ManuelNotManni";
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("TRN-Api-Key", "YOUR API KEY GOES HERE");
// Simplifying Uri creation:
var uri = new Uri($"https://api.tracker.gg/api/v2/rocket-league/standard/profile/epic/{epicId}");
var result = string.Empty; // C# prefers lowercase string
try
{
var response = await httpClient.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
result = await response.Content.ReadAsStringAsync();
}
else
{
Console.WriteLine($"Unable to retrieve data for {epicId}.");
Console.WriteLine($"Statuscode: {response.StatusCode}");
Console.WriteLine($"Reason: {response.ReasonPhrase}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Error:\n{ex}");
Console.ReadLine();
}
finally
{
httpClient.Dispose();
}
This happens when we violate the Firewall rule set by Cloudflare, you can visit this blog for more details.
https://community.cloudflare.com/t/community-tip-fixing-error-1020-access-denied/66439

Difficulty receiving an HTTP Response from API -- Bad Request Error

I'm attempting to pass username/password from an application to the API to receive a token authorization key. When I attempt to do so, I receive a 400 Bad Request error and I cannot figure out why. Below is the method in question:
public User UserAuthentication(string username, string password)
{
string endpoint = baseURL + "/TOKEN";
// Could be POST maybe
string method = "POST";
Credential jsonObj = new Credential
{
grant_type = "password",
username = username,
password = password
};
string jsonStr = JsonConvert.SerializeObject(jsonObj);
WebClient wc = new WebClient();
//x - www - form - urlencoded
wc.Headers[HttpRequestHeader.ContentType] = "application/x - www - form - urlencoded";
wc.Headers.Add("Access-Control-Allow-Headers", "content-type");
wc.Headers.Add("Access-Control-Allow-Origin", "*");
wc.Headers[HttpRequestHeader.Authorization] = "Bearer <token>";
wc.Headers.Add("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, OPTIONS");
string header = wc.Headers.ToString();
try
{
string response = wc.UploadString(endpoint, method, jsonStr);
return JsonConvert.DeserializeObject<User>(response);
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I've messed around altering just about everything in this method in search of a fix.
What I've done:
/TOKEN was /values & /api/values
POST method was GET -- With this, I received a "Cannot send a content-body with this verb-type." error.
ContentType was changed to "application/json"
Access-Control-Allow-Origin had the baseURL
Checked the format of header & body:
Header:
{Content-Type: application/x - www - form - urlencoded
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Origin: *
Authorization: Bearer <token>
Access-Control-Allow-Methods: POST, PUT, GET, DELETE, OPTIONS}
Body:
{"grant_type":"password",
"username":"test#gmail.com",
"password":"password123"}
I obviously have something wrong in my request, I've just run out of ideas to try. I'm not entirely sure if UploadString() is the correct method to be using in this situation, but I couldn't find another method in the WebClient class that would be better. Any help to try and push me in the right direction would be very much appreciated.
So what I think you are trying to do is a form-urlencoded post to a "token" endpoint with a username/password grant. These are typically done like so:
using (var request = new HttpRequestMessage(HttpMethod.Post, new Uri("https://example.com/token"))
{
Content = new FormUrlEncodedContent(new Dictionary<string, string>
{
{ "grant_type", "password" },
{ "username", "username#site.com" },
{ "password", "password12345" }
})
})
{
using (var resp = await _client.SendAsync(request))
{
resp.EnsureSuccessStatusCode();
//await resp.Content.ReadAsAsync<BearerToken>();
// for testing purposes, try this:
var returnData = await resp.Content.ReadAsStringAsync();
Console.WriteLine(returnData);
}
}
You should define this outside all scopes where you need to do Http requests:
private static readonly HttpClient _client = new HttpClient();
So, first off, try to stick with HttpClient. Other patterns such as WebClient are considered legacy.
Next, CORS headers are typically returned from the server when an OPTIONS call is sent to the server. You aren't doing that here, and you should never have to worry about that kind of stuff inside a C# program running from your computer. So you can drop the access-control header stuff.
Form-urlencoded data is not JSON data. It's a different way to format data. If you want to send JSON data, you should use the content-type application/json
Finally, you are trying to add an Authorization header. But that doesn't make much sense as you are trying to authenticate yourself to become authorized. If you send the right username/password, you will receive a bearer token that you can use in an Authorization header for future requests to said service.
Oh and I forgot to add: Whenever you see an error in the [400,499] range (in this case "400 - bad request") it means that you sent something wrong and the server doesn't understand what you are trying to do. For example: a 401 means you sent invalid or missing authorization information. A 400 means your data was probably malformed.
But I like your question... I can see what you were doing and you tried all kinds of different things.
Download a program called Fiddler if you want to see how HTTP works. It's a great tool to debug your HTTP calls.

HttpClient not returning json value of URI

I am trying to use HttpClient to GET information from Jira, but I am unable to see any of the information. I want to be able to get all the bugs that match certain filters so that I can add them to a table in my program.
I have tried to access Jira with the rest api, but every time I do it says that the issue or project doesn't exist. The thing is that if I enter the URI into the bar at the top of my browser I can see the JSON text that I want. This leads me to believe that the reason my code is not returning these values is because of an authorization issue. I am using basic auth to send my credentials. I also want to add that I used cURL in cmd to test my credentials with basic auth and it worked.
public async Task<JiraModel> GetBugs()
{
using (var client = new HttpClient())
{
string url = "https://myurl.atlassian.net/rest/api/3/project/VCMF";
String username = "username";
String password = "apikey";
String encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("UTF-8").GetBytes(username + ":" + password));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", "Basic " + encoded);
client.BaseAddress = new Uri("https://myurl.atlassian.net/rest/api/3/project/VCMF");
var response = await client.GetAsync(url);
var content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<JiraModel>(content);
}
}
I should be getting the json results in string form by the end of this length of code, but I keep getting a 404 error instead that for this code specifically says "No project could be found with key 'VCMF'".
The issue here is that you're creating the authorization header incorrectly.
The constructor you're using for AuthenticationHeaderValue class takes two arguments: scheme and parameter:
public AuthenticationHeaderValue(string scheme, string parameter)
{
}
The first argument should be the scheme (Basic in this case) and the second, the base64-encoded credentials:
So instead of:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", "Basic " + encoded);
It should be:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", encoded);
Hope this helps!

Get Jira tickets using Jira API and C#

public ActionResult getJiraTickets(string username, string password, string jiraUrl)
{
string queryString = jiraUrl + "/rest/api/2/search";
var client = new HttpClient { BaseAddress = new Uri(queryString) };
var credentials = Encoding.ASCII.GetBytes(username + ":" + password);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(credentials));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync(queryString).Result;
if (response.IsSuccessStatusCode)
{
// use response
}
}
I get StatusCode: 401, ReasonPhrase: 'Unauthorized' in the response.
The queryString is correct because if I hit that URI using the browser I get a JSON response back.
Username and password are correct as well.
What am I doing wrong in the code?
Thanks
I apologise for not posting this as a comment, I don't have enough rep yet to post a comment.
I know you say your username and password are correct but I would double check them because I have taken your code and run it with my login details and Jira Url and it worked as expected.

Unable to create a shared link using the Box API V2

UPDATE: I figured it out and posted the answer below.
All I'm trying to do is update any file attribute. Description, name, anything, but no matter how I format it I get a 403.
I need to be able to modify a file so it can be shared via the Box API from a cloud app. I'm updating someone else's code from V1, but they are no longer available... I've tried many things but mostly just get 403 Forbidden errors.
There are no issues with OAuth2, that works fine and I can list files and folders, but can not modify them. This question is about sharing, but I can't change a description either. The box account is mine and I authenticate with my admin credentials. Any suggestions would be appreciated.
Here is the method I am using. I pass in the fileId and token and I've left out try/catch etc. for brevity.
string uri = string.Format("https://api.box.com/2.0/files/{0}", fileId);
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
client.Headers.Add("Authorization: Bearer " + token);
var response = client.UploadData(uri, postArray);
var responseString = Encoding.Default.GetString(response);
}
Thanks.
Okay, My Homer Simpson moment...
UploadData is a POST, I needed to do a PUT. Here is the solution.
string uri = String.Format(UriFiles, fileId);
string response = string.Empty;
string body = "{\"shared_link\": {\"access\": \"open\"}}";
byte[] postArray = Encoding.ASCII.GetBytes(body);
try
{
using (var client = new WebClient())
{
client.Headers.Add("Authorization: Bearer " + token);
client.Headers.Add("Content-Type", "application/json");
response = client.UploadString(uri, "PUT", body);
}
}
catch (Exception ex)
{
return null;
}
return response;
try changing your content type to 'multipart/form-data'?
I just looked up the api at: https://developers.box.com/docs/#files-upload-a-file
and it looks like the server is expecting a multipart post
here is stack overflow post on posting multipart data:
ASP.NET WebApi: how to perform a multipart post with file upload using WebApi HttpClient

Categories