oAuth : Simple javascript - javascript

I got the following info from another question:
var url = "...";
var accessor = {
token: "...",
tokenSecret: "...",
consumerKey : "...",
consumerSecret: "..."
};
var message = {
action: url,
method: "GET",
parameters: {...}
};
OAuth.completeRequest(message, accessor);
OAuth.SignatureMethod.sign(message, accessor);
url = url + '?' + OAuth.formEncode(message.parameters);
// send request to 'url'
...
Now it says it needs a token. In order to get the token I need a signature. In order to get the signature I need a token.
See the problem? Clearly I am misunderstanding something but what?
There is almost 0 documentation for javascript OAuth , so any help is appriciated.
(note:I am using the tumblr API if that helps)

The way OAuth 1.0 works, you first get a set of temporary credentials (also known as request token). When you ask for request tokens, you use an empty token and secret. The OAuth 1.0 RFC explains that in section 2.11:
When making the request, the client authenticates using only the
client credentials. The client MAY omit the empty "oauth_token"
protocol parameter from the request and MUST use the empty string as
the token secret value.
Then you use the token received to send the user over to grant access and when you get it, you use the token + secret to ask for a new access token which you use to make API calls.
EHL

Related

How to use access token stored in session storage for doing web api call using HttpClient?

I have done login using ajax call and stored the access token in session storage using following code.
$('#btnLogin').click(function () {
$.ajax({
url: 'http://localhost:59983/token',
method: 'POST',
contentType: 'application/json',
data: {
username: $('#txtUsername').val(),
password: $('#txtPassword').val(),
grant_type: 'password'
},
success: function (response) {
sessionStorage.setItem("accessToken", response.access_token);
console.log("Success!!!!");
alert("Login Successful");
},
error: function (jqXHR) {
console.log("Failed!!!!");
$('#divErrorText').text(jqXHR.responseText);
$('#divError').show('fade');
}
});
});
Now after login, I want to use the stored access token for performing api calls using HttpClient from a controller method. I don't know how to pass that stored access token to make api call.
The following code I have written to make api call using HttpClient.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:59983/api/flight");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var responseTask = client.GetAsync("flight");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IList<tblFlight>>();
readTask.Wait();
flights = readTask.Result;
}
else
{
flights = Enumerable.Empty<tblFlight>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
Please suggest me how to use that stored access token ?
When we are dealing with webstorage such as session storage or local storage we are doing it client side using javascript , jquery etc. These storage item cannot be accessed in server side code. They are confined to your local browser and can be accessed from client side code running on browser.
Now for your condition i think you can go for session on server side. The point where you are setting value in local storage , instead of putting there do a ajax call to any actionresult function on server and set the value in session. Later on fetch it on server side. Again if you want that value client side you need to do ajax call again and get it from server side function in controller.
ok, so if I understand correctly, you login and create a token then from your MVC controller you want to call API endpoints and use the stored token for that.
The code you posted seems to be what exists in your MVC controller.
using (var client = new HttpClient())
{
//here retrieve the token from where you stored it
string accessToken = "whatever";
client.BaseAddress = new Uri("http://localhost:59983/api/flight");
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
var responseTask = client.GetAsync("flight");
responseTask.Wait();
var result = responseTask.Result;
if (result.IsSuccessStatusCode)
{
var readTask = result.Content.ReadAsAsync<IList<tblFlight>>();
readTask.Wait();
flights = readTask.Result;
}
else
{
flights = Enumerable.Empty<tblFlight>();
ModelState.AddModelError(string.Empty, "Server error. Please contact administrator.");
}
}
Now, if you call the API endpoint directly from javascript then at that point you will need to have it available to your client so in theory. What you could do is store the token in client side storage as well so you can retrieve it when you need to and I can see you're already doing it on the client side.
If you need it in your MVC controller, then get it from session and pass it through to your API endpoint. In this case, you can use an initial extra call, you get your token on client side anyway so after that just call an extra MVC endpoint, pass the token to it and save it in session. This way to have it both on client side and backend side should you need that.
The MVC, Web API combo is a bit of a bastardization of everything. The reason is that MVC obviously has access to Session, while Web API is supposed to be stateless, thus no Session access. In theory a Web API endpoint which is part of an MVC application can get access to the Session object, although that is something that I would avoid doing. I prefer to keep Web API as a completely separate project but I know that's not always possible.

Access Token error - Graph API getting user profile

I'm using Microsoft graph API to get to login and get a users profile. I have the accessToken. Though I'm trying to get the profile of the user that I got the AccessToken with.
This is my code, am I missing anything here? Just need the users profile. Note: I'm using Cors anywhere through a proxy server, which has worked for getting the code and accessToken.
Thanks for your help!
I've tried adding the resource URL. I've tried changing the headers (you don't need body parameters for GET and DEL requests).
let auth =
"http://localhost:8080/https://graph.microsoft.com/v1.0/me?access_token=";
let client_id = "?client_id=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
let redirect_uri = "&redirect_uri=http://localhost:8100/";
let response = "&response_type=code";
let resource = "&resource=https://graph.microsoft.com";
let scope =
"&scope=openid+https://outlook.office.com/Contacts.read+offline_access";
let url =
auth + token + resource + client_id + redirect_uri;
//let url = 'http://localhost:8080/https://graph.microsoft.com/v1.0/me?access_token=' + token +"&resource=https://graph.microsoft.com";
this.http.get(url, {
headers: {
Authorization: "Bearer " + token,
"Content-Type": "application/x-www-form-urlencoded",
"Access-Control-Allow-Origin": "*",
resource: "https://graph.microsoft.com"
}
});
Expected: to take the AccessToken and get a user's profile like in Part 4 here.
You've got a number of things going on here.
You're specifying both scope and resource properties. These don't belong together. If you're using the v1 Endpoint then you should be using resource, if you're using the v2 Endpoint then you should be using scope. See Scopes, Not Resources in the documentation.
Your url is not correct. The actual URL should look like this for v1:
https://login.microsoftonline.com/common/oauth2/authorize?client_id={id}&scope=https%3A%2F%2Fgraph.microsoft.com&redirect_uri={uri}&response_type=code
or for v2, like this:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={id}&scope=openid+user.read+contacts.read+offline_access&redirect_uri={uri}&response_type=code
Can't use http.get() for this. OAuth's Authorization Code grant starts by redirecting the user to this URL. It will then return the code you then POST back to the /token endpoint to retrieve the access_token and refresh_token.
You need the User.Read scope to retrieve a user's profile (or User.ReadBasic.All to retrieve other user's profiles).
I would recommend using the v2 Endpoint and starting here:
Microsoft v2 Endpoint Primer
Get access tokens to call Microsoft Graph
AAD v2 Endpoint Overview

Invalid input response and secret when verifying google reCaptcha

I am really struggling to get a successful response when doing a post request to the google recaptcha api. I am receiving the following response:
{
"success": false,
"error-codes": [
"invalid-input-response",
"invalid-input-secret"
]
}
I had a look at reCAPTCHA - error-codes: 'missing-input-response', 'missing-input-secret' when verifying user's response (missing details on POST) and followed the answer as closely as possible but with no success.
Here is my file below:
var request = require('request');
module.exports = {
verifyCaptcha: function(req, res) {
var secret = 'SECRET_KEY';
var response = JSON.stringify(req.body.response);
request({
url: 'https://www.google.com/recaptcha/api/siteverify',
method: 'POST',
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `secret=${secret}&response=${response}`,
}, function (err, response, body) {
if (err) {
res.status(500).send({
error: "Could not verify captcha"
});
} else {
res.status(200).send({
message: body
});
}
});
},
}
If anyone has a solution to this problem please let me know!
Due to the docs: https://developers.google.com/recaptcha/docs/verify
invalid-input-secret: The secret parameter is invalid or malformed.
Maybe you have mixed the site_key and the secret_key.
You need to add the user remote IP address.
var user_ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
request({
url: 'https://www.google.com/recaptcha/api/siteverify',
method: 'POST',
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `secret=${secret}&response=${response}&remoteip=${user_ip}`}...
Another thing I see that you are not using template literal, you should change the quotes to ` instead of '.
OR, You should use a ready-made module for reCaptcha, like this one:
https://www.npmjs.com/package/recaptcha
For reCAPTCHA Enterprise, check the official docs: https://cloud.google.com/recaptcha-enterprise/docs/create-assessment.
In short, you need to use the library that Google provides:
const { RecaptchaEnterpriseServiceClient } =
require('#google-cloud/recaptcha-enterprise');
const client = new RecaptchaEnterpriseServiceClient();
const [ response ] = await client.createAssessment({...});
RecaptchaEnterpriseServiceClient requires a service account to be created beforehand as described here. The key for that account with the right roles set can then be read by the app. Check the arguments of the constructor to see the available options to pass the data if the file cannot be retrieved automatically.
var response = JSON.stringify(req.body.response);
The stringifying here is probably the cause of the invalid-input-response error.
If your body is something like {"g-recaptcha-response": "..."}, you need to pull out the response value and pass that directly in your post.
Regarding invalid-input-secret, if you have set up your key and secret through the classic interface at https://www.google.com/u/1/recaptcha/admin/create, then you shouldn't have a problem.However if you set up a key with recaptcha Enterprise on Google Cloud, then it requires that you do Oauth authentication to the Google Cloud API and then use the create.assessment endpoint to get back information on the validity of the user. As Yuuhn implied, the Google provided library makes interaction with recaptcha Enterprise easier, without a lot of documentation digging to find where your REST API calls need to go.

User credentials required: Google Cloud Print Submit API

I am trying to access the Submit API that is apart of the Google Cloud Print however I am running into the error "User credentials required".
I am able to get all the way through authentication and am able to retrieve my access token. I was following this guide https://developers.google.com/cloud-print/docs/appDevGuide
I do not know where it is going wrong. Does anyone know where the credentials are supposed to be inputted?
Here is my code for this portion:
function submitPrintJob(token){
try{
var params = {'printerid':'PRINTER_ID','title':'Test Print Job','ticket':{"version": "1.0", "print": {}},'contentType':'application/pdf'};
var response = https.post({
url: 'https://www.google.com/cloudprint/submit',
body: params,
headers: {'Authorization':'Bearer ' + token}
});
log.debug('submitPrintJob','Response - ' + response.body);
}catch(e){
log.error('submitPrintJob','Error - ' + e.message);
}
}
This code is being in done in Netsuite which is where the https.post API is coming in. I also am aware that I am not sending a document through but I at least need to get past this step. I am getting this error using Postman as well.
Editing to add the portion where I get the token:
I send a request to: https://accounts.google.com/o/oauth2/v2/auth
Parameters:
response_type: code,
scope: https://www.googleapis.com/auth/cloud-platform.read-only,
state: state_parameter_passthrough_value,
redirect_uri: scriplet url
client_id: client id
Google oauth returns a authorization code. I exchange the code for a token this way:
function getToken(code){
try{
var params = {'code':code,'client_id':CLIENT_ID,'client_secret':CLIENT_SECRET,'redirect_uri':REDIRECT_URI,'grant_type':'authorization_code'}
var response = https.post({
url: 'https://www.googleapis.com/oauth2/v4/token',
body: params,
headers: {'Content-Type':'application/x-www-form-urlencoded'}
});
var token = response.body.access_token;
submitPrintJob(token);
}catch(e){
log.error('getAuthCode','Error - ' + e.message);
}
}
As I thought, the problem is how you are getting the access token. In order to get a valid access token to do your cloud print business, you need to include the proper scope. That means that your params object should like like this:
var params = {'code':code,'client_id':CLIENT_ID,'client_secret':CLIENT_SECRET,'redirect_uri':REDIRECT_URI, 'scope': 'https://www.googleapis.com/auth/cloudprint', 'grant_type':'authorization_code'}
This should give you a valid access token to interact with Google Cloud Print. I hope it helps!

Best way to replace left and right parenths in a Get request

For my GET request, my server is rejecting it with status: 403, "HTTP/1.1 403 Forbidden"
My GET request object as is follows :
"{"method":"GET","url":"api/myapi/GETstuff","params":{"from":"2017-06-02","to":"2017-06-02","myData":"DATA (AND SOME/MORE DATA)"}}"
The javascript code is:
function getMyData(params){
var url = 'myapi/getStuff';
var req = {
method: 'GET',
url: url,
params: params
};
$http(req) // details omitted for brevity
.success()
.error();
}
I believe the problem is special characters send to the IIS server (such as parenths, and / char), which I need to encode the params array before the GET request is sent via the Angular $http() service.
In order to encode the left/right parenths, and the / char, I'm trying:
request.params.myData = request.params.myData.replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\//g, '%2F')
However, my server is still rejecting the request.
And I doing something wrong?
You're getting a Forbidden error. Sure you don't need to authenticate or pass a token?
Before getting too manual, I'd suggest trying JSON.stringify(obj) and as a second pass, encodeURIComponent(obj)
If you're posting a valid JSON object, you might want to consider POST instead of GET, if you have backend access.

Categories

Resources