Ad

HTTP Post OAuth 2 "Check The `grant_type` Parameter"

- 1 answer

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

Ad

Answer

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.

Ad
source: stackoverflow.com
Ad