I want to have a capability in my application that allows users to Authorize Bitbucket. I have followed https://confluence.atlassian.com/bitbucket/oauth-on-bitbucket-cloud-238027431.html.
The following works and brings the Bitbucket authorization screen as expected:
https://bitbucket.org/site/oauth2/authorize?client_id={client_id}&response_type=code
However, this part emits an error about invalid Grant.
$ curl -X POST -u "client_id:secret" \
https://bitbucket.org/site/oauth2/access_token \
-d grant_type=authorization_code -d code={code}
I am using request module in Node.js and using the code as follows:
request.post(
'https://bitbucket.org/site/oauth2/access_token',
{
json: {
client_id: config.get('app.bitbucket_client_id'),
client_secret: config.get('app.bitbucket_client_secret'),
code: req.query.code,
grant_type: "authorization_code"
}
}, function (error, response, body) {
// Do something here
}
}
{"result":{"error_description":"Unsupported grant type: None","error":"invalid_grant"}}
Please advice!
Found the answer to my question. Basically, Bitbucket expects data to be sent in body directly instead of JSON. Changing from json to form in the code above fixed it for me.
Related
I am creating React Native app using Expo and used its inbuilt Facebook.useAuthRequest to generate a response when a user logs in. When I create a response type of Token I am able to take this token and send it to my backend API that successfully uses it to get the user details.
However I had hoped to implement a response type of code and use this on the backend API generate the access Token and then request the user details - as I believe this is the most secure option when sending the code to my server.
The issue that I'm facing is that I keep getting an error when trying to formulate the requst to Graph API and I dont understand why:
error: {
message: 'Missing client_id parameter.',
type: 'OAuthException',
code: 101,
fbtrace_id: 'ARHcoh260kBwj7l9yDHjU-n'
}
I just want to confirm that I believe I have inserted all the correct information into the request, so I am unsure of why this error is saying its missing the cliend_id. Here is my request from my API server:
const { data } = await axios({
url: https://graph.facebook.com/v12.0/oauth/access_token? client_id=${appId} &redirect_uri=${redirectUri} &client_secret=${appSecret} &code=${code},
method: 'get',
});
I just want to confirm that the client_id I have taken from app id I created on the facebook developer page, as well as the client_secret, redirect is the https:// used in the initial request and the code is the code initially received in my client side request.
Thanks in advance for any suggestions :)
Just a quick update on this, I was ablel to reformat the request as I believe it had some errors in the spacing and I moved to using the .env files so now my request looks like this:
const redirectUri = {MY_REDIRECT URL};
const appId = process.env.FACEBOOK_CLIENT_ID;
const appSecret = process.env.FACEBOOK_CLIENT_SECRET;
const { data } = await axios({
url: `https://graph.facebook.com/v12.0/oauth/access_token?client_id=${appId}&redirect_uri=${redirectUri}&client_secret=${appSecret}&code=${code}`,
method: 'get',
});
It seems I have moved onto a new error with the following:
error: {
message: 'Invalid code verifier. Code verifier should be a cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.',
type: 'OAuthException',
code: 1,
fbtrace_id: 'AQKIUad5RRCitb6m977fnFW'
}
I'm a bit stumped for what this means as I have checked and all my values appear correct. My only thought is if I need to do something with the code initially received on the client side?
Ok so I finally figures it out - the issue was the I wasn't sending the code_verifier along with my request to exchange the Auth Code for a token. I ended up sending this code_verifier to my API server then adding this to the request so it looked something like this:
FB.api(
'oauth/access_token',
{
client_id: appId,
client_secret: appSecret,
redirect_uri: redirectUri,
code_verifier: code_verifier,
code: code,
},
function (response) {
if (!response || response.error) {
console.log(!response ? 'error occurred' : response.error);
return;
}
var accessToken = response.access_token;
This then finally gave me the accessToken I was looking for that I can then use to exchange for user details server side.
... and the code_verifier is obtained from request.codeVerifier.
const [request, response, promptAsync] = Facebook.useAuthRequest(...
This question builds on How to get Microsoft Graph API Access token from Node Script?, however, as a first-time user of, I don't have the required reputation for commenting on the accepted answer in that thread.
The thing is, I tried to implement the approach suggested by the accepted answer, but somewhere it goes wrong. The below code is part of an async function, and I can already tell you that the ONEDRIVE_TENANT_URI is of the format XXX.onmicrosoft.com.
const endpoint = `https://login.microsoftonline.com/${process.env.ONEDRIVE_TENTANT_URI}/oauth2/token`;
const requestParams = {
grant_type: "client_credentials",
client_id: process.env.ONEDRIVE_APP_ID,
client_secret: process.env.ONEDRIVE_CLIENT_SECRET,
resource: "https://graph.windows.net"
};
const authResponse = await request.post({
url: endpoint,
form: requestParams
});
authResponse gets, as its body, just a string with the requestParams as defined above filled out.
If I submit the post request via Postman, with the same parameters as x-www-form-urlencoded, I DO get an access_token in the response body.
So... What do I do wrong? Maybe - but I don't think so - it's because this function is invoked by a (for testing purposes) POSTMAN GET request with a json-formatted body?
You can download the sample here. And fill in the credentials in config.js. You can find them from Azure portal.
This is the code to get access token.
auth.getAccessToken = function () {
var deferred = Q.defer();
// These are the parameters necessary for the OAuth 2.0 Client Credentials Grant Flow.
// For more information, see Service to Service Calls Using Client Credentials (https://msdn.microsoft.com/library/azure/dn645543.aspx).
var requestParams = {
grant_type: 'client_credentials',
client_id: config.clientId,
client_secret: config.clientSecret,
resource: 'https://graph.microsoft.com'
};
// Make a request to the token issuing endpoint.
request.post({ url: config.tokenEndpoint, form: requestParams }, function (err, response, body) {
var parsedBody = JSON.parse(body);
console.log(parsedBody);
if (err) {
deferred.reject(err);
} else if (parsedBody.error) {
deferred.reject(parsedBody.error_description);
} else {
// If successful, return the access token.
deferred.resolve(parsedBody.access_token);
}
});
return deferred.promise;
};
You will get the access token successfully.
You've got two issues going on.
The first isn't an issue yet, but it will be once you try to call Microsoft Graph. The resource should be graph.microsoft.net, not graph.windows.net. The graph.windows.net refers to the legacy Azure AD Graph API, not Microsoft Graph.
The other issue, which is the root cause of this error, is await request.post. Request doesn't natively support promises. From the Request the documentation:
request supports both streaming and callback interfaces natively. If you'd like request to return a Promise instead, you can use an alternative interface wrapper for request. These wrappers can be useful if you prefer to work with Promises, or if you'd like to use async/await in ES2017.
Several alternative interfaces are provided by the request team, including:
request-promise (uses Bluebird Promises)
request-promise-native (uses native Promises)
request-promise-any (uses any-promise Promises)
I'm working with Webhooks and I am trying to run a Curl request from my node.js code. I'm using the npm request package to do this. I'm having trouble finding the proper way to convert the Curl request to code in my application that will send the request.
This is the Curl request:
curl -X POST https://tartan.plaid.com/connect \
-d client_id=test_id \
-d secret=test_secret \
-d username=plaid_test \
-d password=plaid_good \
-d type=wells \
-d options='{
"webhook":"http://requestb.in/",
"login_only":true }'
This works fine when I run it in my terminal so I know the credentials work and it is talking to the server.
Here is my Node.js code:
var request = require('request');
var opt = {
url: 'https://tartan.plaid.com/connect',
data: {
'client_id': 'test_id',
'secret': 'test_secret',
'username': 'plaid_test',
'password': 'plaid_good',
'type': 'wells',
'webhook': 'http://requestb.in/',
'login_only': true
}
};
request(opt, function (error, response, body) {
console.log(body)
});
It should return an item but all I am getting is:
{
"code": 1100,
"message": "client_id missing",
"resolve": "Include your Client ID so we know who you are."
}
All the credentials are from the Plaid website and they work in my terminal just fine so I think it's just the way I am writing my Node.js code that is causing the problem.
If anyone could help my find the right way to write the node code so that it does what the curl request does in the terminal that would be appreciated! Thanks!
You may want to use form: instead of data: in your options. Hopefully that will do the trick.
The default method for request is GET. You want a POST, so you have to set that as a parameter. You also have to send the data as JSON according to the documentation. So I believe this should work:
var opt = {
url: 'https://tartan.plaid.com/connect',
method: "POST",
json: {
'client_id': 'test_id',
'secret': 'test_secret',
'username': 'plaid_test',
'password': 'plaid_good',
'type': 'wells',
'webhook': 'http://requestb.in/',
'login_only': true
}
};
See explainshell: curl -X -d for an explanation of what your curl command actually does.
You send a POST request
You send data using using the content-type application/x-www-form-urlencoded
To replicate that with request you have to configure it accordingly:
var opt = {
url: 'https://tartan.plaid.com/connect',
form: {
// ...
}
};
request.post(opt, function (error, response, body) {
console.log(body)
});
See application/x-www-form-urlencoded for more examples.
I'm writing a rule in Auth0 to trigger a verification email if a certain condition is met. To make the example small I have included the code which I am using to send the verification mail (I have removed out the unwanted code).
var url = 'https://myname.au.auth0.com/api/v2/jobs/verification-email';
var token = 'Bearer {{token}}'; //This is where the problem is how do I get the token
var userId = user.user_id;
request.post({
url: url,
headers: {
Authorization: 'Bearer {{token}}',
},
json: {
"user_id": user.user_ID
},
timeout: 5000
},
function(err, res, body) {
console.log(err);
console.log(res);
});
In the body I get the following error
{ statusCode: 400,
error: 'Bad Request',
message: 'Bad HTTP authentication header format',
errorCode: 'Bearer' }
I guess I need to pass in the access token or something like that in the header. How do I get this done?
I also saw the following article (https://auth0.com/docs/email/custom), however I'm not sure what secretToken is?
Starting from the bottom, the article (https://auth0.com/docs/email/custom) is aimed at users that want additional flexibility and use their own custom email handling. The secretToken on that example it's just to illustrate a possible - and very simple - way that their own custom email API could validate that they were being called from Auth0; in conclusion it would work almost as an API key.
If you only need to trigger a verification email through the system provided by Auth0 you're using the correct approach (Management API v2). You have more than one way to obtain a token that allows you to call this API:
Using the client credentials grant
Using the Auth0 Management API v2 Explorer
The second option would be the easiest to get started, but do take in consideration that there's a deprecation notice for that one.
Once you obtain the token, you also need to correctly pass it to the API. The code you showed may be only sample code, but make sure that you don't end up including the Bearer scheme twice, more specifically var token = 'Bearer {{token}}'; should instead just be var token = '{{token}}'; and then you would use the token variable when creating the HTTP header.
Just created the below empty rule that will get called when user tries to login and email is not yet verified and it works like a charm :D
function (user, context, callback) {
if (!user.email_verified) {
console.log("User is: " + user.user_id);
var ManagementClient = require('auth0#2.6.0').ManagementClient;
var management = new ManagementClient({
token: auth0.accessToken,
domain: auth0.domain
});
var new_userobj = {user_id:user.user_id};
management.sendEmailVerification(new_userobj,callback(new UnauthorizedError('Please click on the link in the email we have sent you to continue to login.')));
} else {
return callback(null, user, context);
}
}
I received the same error when using the wrong token, though for a different api call. I recreated your issue by using a user's access_token obtained by calling {{api-audience}}users/{{user_id}}. That token should look something like this: A1bCd2efg34IJkl5
Try using a client's access_token obtained by making this call:
curl --request POST \
--url https://{{domain}}/oauth/token \
--header 'content-type: application/json' \
--data '{
"client_id":"{{client_id}}",
"client_secret":"{{client_secret}}",
"audience":"{{audience}}",
"grant_type":"client_credentials"
}'
That token will be a full JWT.
I wrote a program in node.js to fetch the access token to call the box apis, unfortunately I am getting an error "invalid_client" which is either "client ID or secret are wrong" as per the documentation. I am pretty sure that both client id and secret are correct since it worked fine for me while doing ajax calls from UI.
Here is the piece of code I am using
{{{
if(queryData && queryData.code) {
var code = queryData.code;
var data = {
"grant_type" : 'authorization_code',
"client_id" : 'alpha-numeric-id',
"client_secret" : 'alpha-numeric-secret',
"code": 'actual-code-given-in-redirect-uri'
};
var options = {
'url': 'https://www.box.com/api/oauth2/token',
'proxy': 'http://corporate-proxy-url:port',
'headers': {
'accept': 'application/json',
'accept-language': 'en'
},
'json': data,
'timeout': 5000
};
request.post( options, function ( err, response, body ) {
if ( err ) {
console.log("====error====");
} else {
console.log("====success=====");
console.log(response.statusCode);
console.log(body);
}
} );
}
}}}
It would be helpful if someone could figure out whats wrong in my code.
Thanks in advance.
Looks like you're hitting the wrong URL: No www.box.com/api for any API calls AFAIK
According to the documentation, it's app.box.com/api/oauth2/authorize? for your first OAuth2 call to do the Authorize and api.box.com/oauth2/token for the Token call, and all subsequent API calls. api.box.com/2.0/
So step 1 : Authorize:
GET https://app.box.com/api/oauth2/authorize?response_type=code&client_id=MY_CLIENT_ID&state=security_token%3DKnhMJatFipTAnM0nHlZA
Step 1.5 user logs onto Box, and you get called back by Box...
Step 2: Get your token
curl https://app.box.com/api/oauth2/token \
-d 'grant_type=authorization_code&code={your_code}&client_id={your_client_id}&client_secret={your_client_secret}' \
-X POST
Step 3: Call APIs:
curl https://api.box.com/2.0/folders/FOLDER_ID/items?limit=2&offset=0 \
-H "Authorization: Bearer ACCESS_TOKEN"