HTTP Post oAuth 2 "Check the `grant_type` parameter"

399

To match the Content-Type header, you'll need to encode the parameters as application/x-www-form-urlencoded.

To do this, you can change your code to something like:

String body = Uri(queryParameters: <String, String> {
  'grant_type' : 'authorization_code',
  'redirect_uri' : Uri.encodeFull(redirectUri),
  'code' : authCode,
  'client_id' : CLIENT_ID,
  'client_secret' : clientSecret,
}).query;

The invocation is pretty much the same:

Future<http.Response> response = http.post( 
  Uri.parse('https://meta.wikimedia.org/w/rest.php/oauth2/access_token'),
  headers: <String, String>{
    'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
    'Content-Length' : body.length.toString()
  },  
  body: body,
);

Addendum

This can be a bit cleaner, combining both parts into the one invocation:

Future<http.Response> response = http.post(
  Uri.parse('https://meta.wikimedia.org/w/rest.php/oauth2/access_token'),
  headers: <String, String>{
    'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
  },  
  body: <String, String>{
    'grant_type': 'authorization_code',
    'redirect_uri': Uri.encodeFull(redirectUri),
    'code': authCode,
    'client_id': CLIENT_ID,
    'client_secret': clientSecret,
  }
);

Note that the specific Content-Length header is not necessary, as this is calculated on send.

Share:
399
underwhelmingToaster
Author by

underwhelmingToaster

Updated on January 01, 2023

Comments

  • underwhelmingToaster
    underwhelmingToaster over 1 year

    I am implementing the OAuth 2 authorization flow for Wikimedia in my dart app using the following code:

    String jsonString = jsonEncode(<String, String>{
      'grant_type' : 'authorization_code',
      'redirect_uri' : Uri.encodeFull(redirectUri),
      'code' : authCode,
      'client_id' : CLIENT_ID,
      'client_secret' : clientSecret,
    });
    String paramName = 'param';
    String formBody = paramName + '=' + Uri.encodeQueryComponent(jsonString);
    List<int> bodyBytes = utf8.encode(formBody);
    
    Future<http.Response> response = http.post( 
      Uri.parse('https://meta.wikimedia.org/w/rest.php/oauth2/access_token'),
      headers: <String, String>{
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
        "Content-Length" : bodyBytes.length.toString()
      },
      body: bodyBytes,
    );
    

    The response for this is:

    { "error": "invalid_request", "error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.",
    "hint": "Check the `grant_type` parameter", "message": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed." }

    It might have to do with the fact that the content-type is still JSON, even though I defined it in the header as application/x-www-form-urlencoded or because the content-length is -1.

    Header Information from Flutter DevTools

    General Information from Flutter DevTools

  • underwhelmingToaster
    underwhelmingToaster over 2 years
    This still suffers excactly the same problems, only difference is the body is not utf-8 encoded.
  • msbit
    msbit over 2 years
    Interesting. I don't have the appropriate client id etc, but running your code gives me the error provided, whereas running mine gives a different error: {"error":"invalid_client","error_description":"Client authentication failed","message":"Client authentication failed"} which I more or less expected.
  • underwhelmingToaster
    underwhelmingToaster over 2 years
    I removed the Content Lenght Params as in your edit (and removed the redirect uri as it is not required) and now it works. Thanks!