Search code examples
c#oauthoauth-2.0dotnetopenauth

oauth2 authentication c# code is not working


I am trying to consume oauth2 api using auth code. In first step, i received auth by providing client id and secret, and now in 2nd step, i need access token using that auth code. I tried below c# code

var client1 = new RestClient("https://ant.aliceblueonline.com/oauth2/token");
var request1 = new RestRequest(Method.POST);
request1.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request1.AddParameter("code", "xxxxxxxxxxxxxxxxx");
request1.AddParameter("grant_type", "authorization_code");
request1.AddParameter("redirect_uri", "https://ant.aliceblueonline.com/plugin/callback");
request1.AddParameter("client_id", "MM01418");
request1.AddParameter("client_secret", "xxxxxxxxxxxxxx");
IRestResponse response = client1.Execute(request1);

In response, I get

The OAuth 2.0 Client supports client authentication method "client_secret_basic", but method "client_secret_post" was requested. You must configure the OAuth 2.0 client's "token_endpoint_auth_method" value to accept "client_secret_post

Tried a lot but could not resolve it.


Solution

  • First of all as you're working with C# I would like to recommend you to use IdentityModel to interact with any OAuth2 authorization server or OpenId Connect Provider.

    Let's start by the definition of a Client: A client is an application that is allowed to request acces tokens on behalf of the user. In your example your server runing the code you posted is the client.

    To be able to use the token endpoint to request a new access_token a client must be able to prove its identity first, by providing a client_id and client_secret (like a user and password for clients).

    There are two methods for providing this client credentials, from IdentityServer4 documentation about secrets:

    Authentication using a shared secret

    You can either send the client id/secret combination as part of the POST body:

    POST /connect/token
    client_id=client1& client_secret=secret& ...
    

    ..or as a basic authentication header:

    POST /connect/token
    Authorization: Basic xxxxx
    

    In this case, the error response is saying that just one of those methods is allowed, which is Authentication header

    So instead of passing your client_id and client_secret along your request body:

    request1.AddParameter("client_id", "MM01418");
    request1.AddParameter("client_secret", "xxxxxxxxxxxxxx");
    

    you need to concat client_id and client_secret with a collon as separator like "MM01418:xxxxxxxxxxxxxxxx" and apply base64 codification. Then add it to your request as header, of the form Authorization: Basic TU0wMTQxODp4eHh4eHh4eHh4eHh4eHh4. You can do this in c# by using the following code:

    var credentials = string.Format("{0}:{1}", clientId, clientSecret);
    var headerValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(credentials));
    
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", headerValue);
    

    or instead leave this low level details to a library like IdentityModel Nuget Docs that implements the correct requests for you depending on the case.