3

I have the following simple GET request with Basic Auth that works fine from Postman:

enter image description here

I then just copy/paste the C# - RestSharp code snippet from postman into a simple console application:

class Program
{
    static void Main(string[] args)
    {
        var client = new RestClient("https://.....");
        client.Timeout = -1;
        var request = new RestRequest(Method.GET);
        request.AddHeader("X-CSRF-Token", "Fetch");
        request.AddHeader("Authorization", "Basic U0.....==");
        IRestResponse response = client.Execute(request);            

        ....

but the response is: 401 Not Authorized.

I've always used the auto-generated snippets form Postman with no problems so far. But now I'm facing this issue, apparently sth is missing from the request made with C# code.

Any advice or pointers would be much appreciated!

UPDATE: Using curl on windows 10 the request works ok. This is what I used:

curl --location --request GET "https://....." --header "X-CSRF-Token: Fetch" --header "Authorization: Basic ......"

The auth token is exactly the same in both cases, in curl it works in RestSharp it doesn't.

Giorgos Betsos
  • 71,379
  • 9
  • 63
  • 98
  • 1
    Maybe a CORS issue? Another tip is to clear session cookies from postman. – Max Sep 19 '21 at 19:02
  • @Max I've tried clearing session cookies but it didn't help. If it's a CORS issue then how could I make the request using RestSharp to achieve the same result as Postman? – Giorgos Betsos Sep 19 '21 at 19:06
  • Have you tried what suggested here? https://stackoverflow.com/questions/31833431/restsharp-httpbasicauthentication-example the HttpBasicAuthenticator should do the work – ddfra Sep 19 '21 at 19:20
  • try disabling each header in postman and see . there might be another mandatory header that the server might require and is autogenerated in postman – PDHide Sep 19 '21 at 19:23
  • Screenshot seems to show a Cookie but your code does not – Caius Jard Sep 19 '21 at 19:27
  • Maybe you need a `client.CookieContainer = new CookieContainer()`? – Steeeve Sep 19 '21 at 19:28
  • @ddfra Yes, I've already tried this, it didn't work – Giorgos Betsos Sep 19 '21 at 19:47
  • @CaiusJard I've tried adding the cookie to my code, it didn't work. Also, in initial Postman request the cookie is not there, it is only added after the first response is obtained. – Giorgos Betsos Sep 19 '21 at 19:48
  • I know it's out of the scope of your question, but I suggest to use HttpClient, which is part of the framework and not a third party library – ddfra Sep 19 '21 at 19:50
  • Have you tried HttpClient, that is part of System.Net.Http namespace? – Meer Sep 19 '21 at 19:51
  • @ddfra honestly, if the third party library does s as nice job of managing the lifecycle of the client, or maybe uses the dedicated factory, I'd defer to it.. Refit is nice – Caius Jard Sep 19 '21 at 21:44
  • @CaiusJard yeah you're absolutely right... it's just that in this case HttpClient does its job pretty well. – ddfra Sep 19 '21 at 21:55
  • Try to intercept the request with something like Fiddler, in both cases, then compare full requests (all headers). – Evk Sep 22 '21 at 09:04
  • maybe a `https` https://stackoverflow.com/questions/35308945/accessing-https-url-from-console-application-using-c-sharp – iSR5 Sep 25 '21 at 12:29
  • 2
    @GiorgosBetsos Maybe a stupid idea but a simple one: Did you properly apply basic encoding to your username/password? Code should look something like this: `string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1")) .GetBytes(username + ":" + password)); httpWebRequest.Headers.Add("Authorization", "Basic " + encoded);` – Dominik Sep 27 '21 at 09:19
  • @Dominik Yes encoding is correct, I cross checked the value I'm using with the value generated by Postman and they are exactly the same. – Giorgos Betsos Sep 27 '21 at 10:39
  • @GiorgosBetsos Did you check the difference between the requests with something like fiddler? – Dominik Sep 27 '21 at 10:43
  • @GiorgosBetsos did you tried generate another code snippet (cURL as example) and ran it? It works or not? – Alexander I. Sep 28 '21 at 09:31
  • Maybe check if there is some weird special character in your Authorization Header string, which needs escaping. – kopaka Sep 28 '21 at 13:08
  • @AlexanderI. I tried with curl and it worked, but I still can't understand why restsharp doesn't work – Giorgos Betsos Sep 30 '21 at 19:03
  • @GiorgosBetsos try to change [PreAuthenticate](https://learn.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest.preauthenticate?view=net-5.0) property in your request. – Alexander I. Sep 30 '21 at 20:05
  • @GiorgosBetsos, did you solved this issue? I have same – Emil Sabitov Mar 20 '22 at 16:09

3 Answers3

1

It's not a great answer, but I think there must be some other header or property within your Postman request that is missing from your C# example.

To double check, I used a Postman request with no username and a password as per your example. I then copied the header stringcopied the header from Postman

A quick unit test later and the code I used have many times before (very similar to the comments)

    [Test]
    public void PostmanEncodesCredentialsProperly()
    {
        var password = "a temporary cred";
        var expected = "Basic OmEgdGVtcG9yYXJ5IGNyZWQ=";

        var header = GetBasicAuthHeader(string.Empty, password);

        Assert.That(header, Is.EqualTo(expected));
    }

    private string GetBasicAuthHeader(string user, string password)
    {
        var cred = $"{user}:{password}";
        var encoded = Convert.ToBase64String(Encoding.UTF8.GetBytes(cred));
        return $"Basic {encoded}";
    }

shows that Postman is encoding exactly what you would expect.

ste-fu
  • 6,879
  • 3
  • 27
  • 46
0

Here's my example, check your ssl. The endpoint setting has Nginx, SSL self-signed certificate, basic auth.

using System;
using RestSharp;
using RestSharp.Authenticators;

namespace StackOverflow
{
  class Program
  {
    static void Main(string[] args)
    {
      var client = new RestClient("https://10.0.1.98");
      client.Timeout = -1;
      // Auth
      client.Authenticator = new HttpBasicAuthenticator("patricio", "myStrongPwd");
      // bypass self-signed certificate verification
      client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
      var request = new RestRequest(Method.GET);
      IRestResponse response = client.Execute(request);   
      Console.WriteLine(response.StatusCode);
    }
  }
}
Nimantha
  • 6,405
  • 6
  • 28
  • 69
Pato
  • 462
  • 2
  • 4
  • 11
  • 1
    Maybe just to add to this answer: This completely bypasses certificate validation and therefore makes you vulnerable to plenty attacks - especially man-in-the-middle, where someone could steal your credentials. – Dominik Sep 27 '21 at 09:22
  • I tried this, problem still remains – Giorgos Betsos Sep 27 '21 at 18:33
  • @Giorgos I think you also need to add Headers, ContentType and Accept request type. Like this `req.Headers.Add("SOAPAction: urn:sap-com:document:sap:rfc:functions:........");` – Pato Sep 27 '21 at 19:29
  • @Giorgos is this your problem ? https://stackoverflow.com/a/42448670/9925593 – Pato Sep 30 '21 at 11:16
-1

I could not spot a ContentType, UserAgent for the Request processing you have implemented.

if (RequestMethod == MethodENU.RequestMethod.GET)
{

    webReqeust = (HttpWebRequest)WebRequest.Create(string.Format("{0}{1}", requestURI, queryString));
    if (authorizationHeader == true)
    {
        webReqeust.Headers.Add("Key", "KeyValue");
    }

    webReqeust.Method = RequestMethod.ToString(); // ReqeustMethod Object Is an ENUM of possible Reqeust Methods, GE
    if (ContentType == MethodENU.ContentType.JSON) // Using Different Content Types Accodring to Requirement.
    {
        webReqeust.ContentType = "application/json";  
    }
    else if (ContentType == MethodENU.ContentType.FORM_DATA)
    {
        webReqeust.ContentType = "multipart/form-data";
    }
    webReqeust.UserAgent = "Mozilla/5.0"; // Setting a UserAgent
    resp = (HttpWebResponse)webReqeust.GetResponse();
    using (StreamReader reader = new StreamReader(resp.GetResponseStream()))
    {
        responseData = reader.ReadToEnd();
    }
}

Enumerations used in the above sample code.

public enum RequestMethod
{
    GET,
    POST,
    PUT
}

public enum ContentType
{
    JSON,
    FORM_DATA
}

Also, Did you try to catch the request and response using some tool like Fiddler? How are the responses in both the cases, PostMan and CodeBase?