AADSTS90014: The request body must contain the following parameter: 'grant_type' - oauth-2.0

I am trying to send a post request to receive my access token from https://login.microsoftonline.com/common/oauth2/v2.0/token. When I tried this in my REST client, it works, but when I try to integrate it to my app, it sends me a error 400 Bad Gateway, with the message AADSTS90014: The request body must contain the following parameter: 'grant_type'. I tried searching for answers, and found out that I need to implement headers in my post request, so I did that, but it still won't work. Any ideas?
Http Imports:
import { HttpClient, HttpHeaders, HttpRequest } from '#angular/common/http';
Call to post request:
var url=this.outlook_authentification_endpoint+"token";
var query_parameters=JSON.stringify({grant_type:"authorization_code", client_id:this.outlook_client_id, code: this.outlook_user_code, client_secret: this.outlook_secret_key, redirect_uri: this.outlook_redirect_uri});
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
})
};
this.query_service.postOutlook(url, query_parameters, httpOptions, (data)=>
{
console.log(data);
});
Call to the post function:
public postOutlook(url, query, headers, callback)
{
this.operation_pending=true;
this.http_client.post(url,query, headers).subscribe((data)=>
{
this.operation_pending=false;
callback(data);
});
}
Can anyone see where my error is?

You are using wrong OAuth2 flow (the way of getting tokens). You are using the Auth code grant, which cannot be used in browser applications, because you would have to keep your client secret in JavaScript, which means make it public. So you cannot access the /token endpoint either.
You should use the Implicit grant, which is designed for browser applications. Then you get tokens right into your Angular application without the need of going to the /token endpoint.

Related

How to send request to another server in shelf dart

I need to make a request to my firebase rtdb from my shelf server hosted on 127.0.0.1, I have the url and the db secrets. But whenever i try to make a get request to the db url using the http package, i get a 401 error.
My code:
import 'dart:io';
import 'package:http/http.dart';
import 'package:firebase/firebase_io.dart';
class FirebaseLocalClient {
void putSudokuBoard() async {
var a = await get(
Uri.parse(
"<db url>"),
headers: {
"Authorization": "Bearer <your database secret>",
'Content-Type': "application/js"
});
print(a.statusCode);
//print(a.runtimeType);
}
}
void main(List<String> args) {
FirebaseLocalClient().putSudokuBoard();
}
I call this code from a shelf server(similar to the code in main function), but running it here itself recieves a 401 error.
I am not able to understand why i am recieving a 401 error, i have the db secrets and yet i am unable to get the data at that location. I tried using the admin sdk json but recieved 401 on that too
The output when i use a.body:
The output when i use a.statuscode:
If you are using the db secrets, it looks like you need to append the auth param.
per https://firebase.google.com/docs/database/rest/retrieve-data#section-rest-uri-params
curl 'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'
Remove the Authorization header and try it in curl

Recieving 400 bad request when trying to exchange authorization code with oauth 2 tokens

I'm trying to connect to an rss api provider 'Inoreader' and I'm using react native. I am able to get the authorization code but when I submit a post request for exchanging with tokens, I get 400 bad request. The response text is undefined. I checked and all their parameters are matching with my app's. I have tried.
This is their documentation: https://www.inoreader.com/developers/oauth
fetch('https://www.inoreader.com/oauth2/token', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Host': 'www.inoreader.com',
'Content-length': '217',
'User-Agent': navigator.userAgent,
'Content-type': 'application/x-www-form-urlencoded'
},
body: JSON.stringify({
'code':`${this.state.auth_code}&redirect_uri=${this.state.gizmos}&client_id=${this.state.userId}&client_secret=${this.state.userKey}&scope=&grant_type=authorization_code`
})
})
.then((res) => {
this.setState({
userName: res.access_token
});
console.log(res.status);
});
I see three problems in your code
You have a fixed Content-length value (217) from the Inoreader example. This way, the server reads just 217 characters of the request and the rest is discarded if the request is longer.
The request Content-type is urlencoded, but you probably don't URL encode the values. You can use the [encodeURIComponent()][1] function to do it.
The /token endpoint requires you to send a client secret, but your application cannot keep it safe, so the secret can easily get compromised. As they write in the guide, the request should be done from a backend. Or you can ask them to support OAuth2 for native apps.

Getting CORS error when I am making Ajax request to /common/oauth2/v2.0/token

Getting CORS error when I am making Ajax request to https://login.microsoftonline.com/common/oauth2/v2.0/token from my application.
Below is the code sample that I am using:
var inputData = {
'grant_type': 'authorization_code',
'code': '<codeValue>',
'redirect_uri': '<returnUrl>',
'client_id': '<client_id>',
'client_secret': '<client_secret>'
};
$.ajax({
url: 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
type: 'post',
contentType: 'application/x-www-form-urlencoded',
dataType: 'application/json',
data: inputData,
success: function (data, text) {
console.log(data.access_token);
},
error: function (data, status, error) {
console.log('failed');
}
});
Browser console is showing below error:
Cross-Origin Request Blocked:
The Same Origin Policy disallows reading the remote resource at https://login.microsoftonline.com/common/oauth2/v2.0/token. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
I would like to know how to get ride of CORS error.
You shouldn't use the Authorization Code Flow to do client-size authentication. It would require that you provide the Client Secret as you're doing here and that is a big no-no.
If you need to handle authentication entirely on the client-size, you need to use the Implicit Flow (aka Client-Side Flow). This allows you to authenticate without passing a client secret and doesn't use a second-stage POST to obtain the token.
I wrote a walk through for how Implicit works that you might find helpful as well: v2 Endpoint and Implicit Grant

Paw not finding access_token from OAuth proxy

I have a use-case where I need to spoof a white-listed Redirect URL locally when performing OAuth 2 authentication.
I'm running a very basic web-server coupled with a hosts file entry for the domain I'm spoofing. I'm able to correctly negotiate my tokens and return them to Paw, but Paw isn't picking up my access_token or refresh_token, it simply displays the raw response:
Here's my server code (with placeholders for sensitive data):
var http = require('http'),
request = require('request');
var PORT = 6109;
var server = http.createServer(function(req, res) {
var code = req.url.split('?')[1].split('=')[2];
request({
url: 'https://<access token URL>/oauth2/token?code=' + code,
method: 'POST',
form: {
'client_id': <client_id>,
'client_secret': <client_secret>,
'grant_type': 'authorization_code',
'redirect_uri': <spoofed redirect URL>
}
}, function(err, response, data) {
data = JSON.parse(data);
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify(data.result));
// I also tried this with the same end-result
// res.writeHead(200);
// res.write('access_token=' + data.result.access_token + '&token_type=' + data.result.token_type + '&refresh_token=' + data.result.refresh_token);
res.end();
});
});
server.listen(PORT, function() {
console.log('Server listening on port %d', PORT);
});
What am I missing? Why isn't Paw finding my tokens?
Here's my configuration for reference:
Some other noteworthy points:
The OAuth provider is non-standard and flubs quite a few things from the spec (my proxy exists in part to patch up the non-standard bits)
The domain for the Redirect URL is real, but the URL does not resolve (this is a part of the reason for the local hosts entry)
I'm not showing this part of the flow, but I am correctly completing the authorization step prior to being given the code value
I think you're probably confused between the Authorization URL and Access Token URL. When you're in Authorization Code grant type for OAuth 2, you're expected to have a user confirmation step in a web page (the Authorization URL).
Which makes me guess that instead, you're expecting instead to use the Password Grant or Client Credentials? Otherwise, if you want to use Authorization URL, you'll need to specify a webpage at the Authorization URL.
Note: I've tried your Node.js script in Paw using the two last grants I mentioned (Password Grant & Client Credentials), and it works nicely.
Update: Following the comments below, I understand more what you are doing. The Authorization Request should (if successful) return a 302 redirect response to the Redirect URL page, and append a code URL query param to it. It seems like you're returning a JSON response with the code instead, so Paw isn't catching it.
According to the OAuth 2.0 spec (RFC 6749), section *4.1.2. Authorization Response*, if granted, the code should be passed as a URL query param (i.e. a ?key=value param in the URL) to the Redirect URL when doing the redirection.
If the resource owner grants the access request, the authorization
server issues an authorization code and delivers it to the client by
adding the following parameters to the query component of the
redirection URI using the "application/x-www-form-urlencoded" format
Quoting the example from the spec, here's how the response of the Authorization Request should look like if it's a success (code is granted):
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
I saw that the Redirect URL contains "my Spoofed Uri".
When we need to use authorization code flow, we provide the authorization code and redirect Uri.
When the URI you are providing does not match the URI saved for the client in Identity server, you will not be able to get the token as the URI does not match with the client authorization code.
For example : Consider client identity in the Identity server be:
Auth Code: "xyx"
Redirect Uri: "www.mylocalhost.com\xyz"
And in your example the combination you are providing is:
Auth Code: "xyx"
Redirect Uri: "<my spoofed uri>"
As these 2 wont match there will be no token received.
I believe if you use the correct URI that is registered with the client in the Identity server, you will be able to receive the token.

Twitter Api Request Token Url Issues

I need help with twitter API. request_token results in an error:
Could Not Authendicate You... Authorization Required.
My code is:
var url="https://api.twitter.com/oauth/request_token?";
url+="&oauth_callback=" +callbackUrl;
$.ajax({
url:url,
type:'POST',
data: {},
async :true,
beforeSend:function(xhr){
xhr.setRequestHeader('Authorization','OAuth oauth_consumer_key="3lqppVjoq7snHzGkvlab7uSix ", oauth_nonce="f7998b22bed5df683dc2f54c0a0679b3 ", oauth_signature="0CSKKi1hy901Mh6uHdLnL%2FDUXwE%3D", oauth_signature_method="HMAC-SHA1", oauth_timestamp= "1458408374 ", oauth_token, "403211404-jJsPD74gOelV7wFcSfoaRwfWAnZqsB9ysXDTO5ox", oauth_version="1.0"');
},
success: function(data){
alert(data);
},
error:function(error){
alert(JSON.stringify(error));
}
});
There are a couple of things I can immediately see:
The Twitter docs state that you should include all oauth_* parameters in the header if you are using HTTP-header based OAuth (this includes the oauth_callback parameter).
The oauth_token parameter is not part of the initial request token flow (because you haven't obtained a token yet) and so should be removed from the Authorization header.
Obviously check that your signature is correct which you can do with an online signature generator such as this one.

Resources