Connecting to bank account with OAuth2.0 and Google App Scripts - google-app-engine

My bank offers to connect to their APIs using OAuth2. I want to create an App Script to autmatically write my transactions to google docs. This is my first time using OAuth and I can't seem to get the access token. Below I have pasted my attempt at receiving an access token, but the site refuses my request. Below my code example are two code examples (one for Node and one for Python) which are provided by the bank. Are there any obvious mistakes that I don't see?
My code:
function get_auth_token() {
var identityServerUrl = "https://auth.sbanken.no/identityserver/connect/token"; // access token endpoint
var clientId = '...'
var secret = '...'
var basicAuth = Utilities.base64Encode(encodeURIComponent(clientId) + ":" + encodeURIComponent(secret)); // create basicAuth header value according to Oauth 2.0 standard
var response = UrlFetchApp.fetch(identityServerUrl, {
headers: {
'Accept': 'application/json',
'customerId' : clientId,
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + basicAuth}
});
}
Node code from the bank:
exports.getAccessToken = () => {
var identityServerUrl = "https://auth.sbanken.no/identityserver/connect/token"; // access token
endpoint
var clientId = credentials.clientid; // application key received from API Beta in the internetbank
var secret = credentials.secret; // password received from API Beta in the internetbank
var basicAuth = btoa(encodeURIComponent(clientId) + ":" + encodeURIComponent(secret)); // create basicAuth header value according to Oauth 2.0 standard
var accessToken;
// request accessToken (the basic auth data is put on the request header prior to sending the request)
let response;
var promise = new Promise(function (resolve, reject) {
request
.post(identityServerUrl)
.send('grant_type=client_credentials')
.set('Authorization', "Basic "+basicAuth)
.set('Accept', 'application/json')
.set('customerId', credentials.userid)
.end(function(err, res){
if (err || !res.ok) {
console.log(err);
reject();
} else {
console.log('yay got ' + JSON.stringify(res.body));
resolve(res.body);
}
});
});
Python code from the bank:
CLIENT_ID = '' # Get from https://secure.sbanken.no/Personal/ApiBeta/Info/
SECRET = '' # Get this from https://secure.sbanken.no/Personal/ApiBeta/Info/
AUTH_URL = 'https://auth.sbanken.no/identityserver/connect/token'
ACCOUNTS_URL = 'https://api.sbanken.no/exec.bank/api/v1/accounts'
CUSTOMER_ID = '' # Your own personnummer
def get_auth_token(auth_url, client_id, secret):
headers = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
}
body = {'grant_type': 'client_credentials'}
urlencoded_client_id = urllib.quote(client_id)
urlencoded_secret = urllib.quote(secret)
auth_string_to_be_b64encoded = '{}:{}'.format(
urlencoded_client_id, urlencoded_secret)
b64encoded_auth_string = base64.b64encode(auth_string_to_be_b64encoded)
headers['Authorization'] = 'Basic {}'.format(b64encoded_auth_string)
r = requests.post(url=auth_url, headers=headers, data=body)
auth_token = r.json()['access_token']
return auth_token

From the code samples, I'd bet that you need to pass grant_type=client_credentials as part of the request. There are two ways you can do this:
Add it to the URL https://auth.sbanken.no/identityserver/connect/token?grant_type=client_credentials
Include it as the payload of the UrlFetchApp.fetch() request (this would be the more "correct" approach):
var response = UrlFetchApp.fetch(identityServerUrl, {
headers: {
'Accept': 'application/json',
'customerId' : clientId,
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + basicAuth
},
payload: 'grant_type=client_credential'
});
Unfortunately, I can't verify if that's all you'll need to do to make it work, but it should get you going in the right direction. Also, I'd really recommend you try to configure this through Google's OAuth2 library, although it isn't the most straight-forward to implement.

The answer can be found in Diego's post, but I also made some other changes to the code:
var headers = {
'Authorization': 'Basic ' + basicAuth,
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
};
var options = {
"method" : "get",
"headers" : headers,
"payload" : {'grant_type': 'client_credentials'},
};
var response = UrlFetchApp.fetch(identityServerUrl, options);

Related

Cookies not being stored in browser

Working with Next.js and Django Rest Framework, I'm authenticating users using JWT. First, when the user successfully logs in to the page, a cookie (which contains the JWT token) is sent to the browser. When the user tries to access a specific page, this cookie is used to validate the petition. I'm having trouble storing the cookie in the browser.
Django | login function
#api_view(['POST'])
#permission_classes((permissions.AllowAny,))
def login(request):
...
response = Response()
response.set_cookie(key='jwt', value=token, httponly=True, max_age=86400)
response.data ={
'message': 'success',
}
return response
And here is how I'm fetching /api/login
Next | Login.js
var axios = require('axios');
var FormData = require('form-data');
var data = new FormData();
data.append('email', this.state.email);
data.append('password', this.state.password);
data.append('X-CSRFToken', csrftoken);
data.append('mode', 'same-origin');
data.append('Content-Type', 'application/json');
var config = {
method: 'post',
credentials: 'include', #I'm probably having issues with this
url: 'http://localhost:8000/api/login',
data : data
};
axios(config)
.then(res=> {
console.log('success'); #I got logged, but cookie is not stored
})
.catch(
error=>{this.setState({isError:true})}
);
Here is the set-cookie in the browser:
But JWT is missing on storage:
As you can see, in both of them I'm receiving the cookie named JWT. But it's not being stored in the browser.
Thank you in advance for your time and answers!
It's important to note is that mode, credentials aren't supported for configuring Axios.It works in fetch api because those options are part of the Request API (docs for mode are here).
Axios uses a XMLHttpRequest under the hood, not Request.
Try this :
var axios = require('axios');
var FormData = require('form-data');
var data = new FormData();
data.append('email', this.state.email);
data.append('password', this.state.password);
const headers = {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken
}
var config = {
method: 'post',
withCredentials: true,
url: 'http://localhost:8000/api/login',
data : data,
{headers: headers}
};
axios(config)
.then(res=> {
console.log('success');
})
.catch(
error=>{this.setState({isError:true})}
);
------------------------------OR----------------------------------
put this at top:
axios.defaults.withCredentials = true
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
This Must in django:
settings.py:
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'http://localhost:3000',
'http://localhost:8000'
)

Cannot generate embed token using access token in power bi

I'm trying to be understand authorization mechanism in power bi API
I would embed a report in my web app.
I have done the steps as mentioned in docs
Actually I would get report embedded url then use power bi JS API to embed the report.
Getting access_token is successful
var options = {
'method': 'POST',
'url': `https://login.microsoftonline.com/${process.env.TENANT_ID}/oauth2/token`,
'headers': {
'Content-Type': 'multipart/form-data'
},
formData: {
'grant_type': process.env.GRANT_TYPE,
'client_id': process.env.CLIENT_ID,
'client_secret': process.env.CLIENT_SECRET,
'resource': "https://analysis.windows.net/powerbi/api",
'Scope': "https://analysis.windows.net/powerbi/api/.default"
}
};
Now I try to get embedded token for report in group
var data = { accessLevel: "View", datasetId: "5b11d62a-803e-46c9-83f3-*****" };
var config = {
method: 'post',
url: `https://api.powerbi.com/v1.0/myorg/groups/${process.env.GROUP_ID}/reports/${process.env.Report_ID}/GenerateToken`,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${JSON.parse(response).access_token}`
},
data: data
};
let embedtoken
try {
embedtoken = await axios(config)
}
catch (e) {
console.log(e)
}
context.res = {
// status: 200, /* Defaults to 200 */
body: JSON.parse(response).access_token
};
I get error 400 response
But When I generate an embed token for dashboard I get a valid token. But of course that's not working with get report API
My goal is to get report infos. For information I get get that using the access token but it's not safe
For POST API requests, data should be passed in string format. This can be done by using for example, JSON.stringify(data).
Refer below code snippet which should resolve the error.
var config = {
method: 'post',
url: `https://api.powerbi.com/v1.0/myorg/groups/${process.env.GROUP_ID}/reports/${process.env.Report_ID}/GenerateToken`,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${JSON.parse(response).access_token}`
},
data: JSON.stringify(data) };

How to pass bearer token in $window.open url

I am opening the url without authentication using below code,
$window.open(downloadUrl);
I want to use below authorization
Authorization': 'Bearer ' + '123hrwertjwtjwjrtr',
i have used below code but it is not working,
var params =
{
'Authorization': 'Bearer ' + '123hrwertjwtjwjrtr',
'Content-type': 'application/x-www-form-urlencoded',
};
var downloadUrl = somedummyurl;
var url = [downloadUrl, $.param(params)].join('?');
$window.open(url);
Can anyone suggest how to add bearer token while calling the api url.
In api am using httpget method and used authorize tag..

Auth0 NodeJS Authentification Refused using npm request

I'm facing a problem, I tried to connect to Auth0 API to enable a strong identification on my WebApp.
For context :
Front-End : I'm using an angularJS front, and there I implemented the Lock Library to manage the Auth0 popup by following this webapp-specific tutorial.
Back-End : NodeJS & Express server, in order to verify the user's authentification, I use the npm lib "request" to call the Auth0 API.
If i understand well, a click on the auth0 widget sends a request to the specified endpoint URL, and it's received by the back-end:
app.get('/auth0CallbackURL', function (req, res) {
console.log(req.query.code);
var auth0code = req.query.code;
var client_secret = PROCESS.ENV.SERCRETID;
var domain = PROCESS.ENV.DOMAIN;
var client_id = PROCESS.ENV.CLIENTID;
var redirectUrl = PROCESS.ENV.REDIRECTURL;
var request = require('request'); // request-promise
var requestParams = {
url: 'https://mycompanydomain.auth0.com/oauth/token?client_id='+client_id+'&redirect_uri='+redirectUrl+'&client_secret='+client_secret+'&code='+auth0code+'&grant_type=authorization_code',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}
And then I call request() to get back the access_token and verify the authentification.
request(requestParams, function(err, data) {
if (err) {
console.log('Err:', err);
} else {
console.log('response body: ', data.body)
}
But the only result I get is :
{
"error": "access_denied"
"error_description": "Unauthorized"
}
At the begining i thougt it was my Auth0 configuration that's didn't allow my authentification, but it seems that there are OK.
Thanks in advance for your replies.
As per the page you linked, you need to pass the following information:
client_id=YOUR_CLIENT_ID
&redirect_uri=https://YOUR_APP/callback
&client_secret=YOUR_CLIENT_SECRET
&code=AUTHORIZATION_CODE
&grant_type=authorization_code
in the request body and with a content type of application/x-www-form-urlencoded.
You're setting the content type correctly, but then are passing the data in the URL query component and instead you need to pass it the POST request body.
Using request package you should do the following:
var requestParams = {
url: 'https://mycompanydomain.auth0.com/oauth/token',
method: 'POST',
body: 'client_id=' + client_id +
'&redirect_uri=' + redirectUrl +
'&client_secret=' + client_secret +
'&code=' + auth0code +
'&grant_type=authorization_code',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}

Nodejs sending external API POST request

i am trying to send a POST request from my angularjs controller to the nodejs server which should then send a full POST request to the external API and this way avoid CORS request as well as make it more secure as i'm sending relatively private data in this POST request.
My angularjs controller function for making the post request to the nodejs server looks like this and it works fine:
var noteData = {
"id":accountNumber,
"notes":[
{
"lId":707414,
"oId":1369944,
"nId":4154191,
"price":23.84
}
]
}
var req = {
method: 'POST',
url: '/note',
data: noteData
}
$http(req).then(function(data){
console.log(data);
});
Now the problem lies in my nodejs server where i just can't seem to figure out how to properly send a POST request with custom headers and pass a JSON data variable..
i've trierd using the nodejs https function since the url i need to access is an https one and not http ,i've also tried the request function with no luck.
I know that the url and data i'm sending is correct since when i plug them into Postman it returns what i expect it to return.
Here are my different attempts on nodejs server:
The data from angularjs request is parsed and retrieved correctly using body-parser
Attempt Using Request:
app.post('/buyNote', function (req, res) {
var options = {
url: 'https://api.lendingclub.com/api/investor/v1/accounts/' + accountNumber + '/trades/buy/',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': apiKey
},
data = JSON.stringify(req.body);
};
request(options, function (error, response, body) {
if (!error) {
// Print out the response body
// console.log(body)
console.log(response.statusCode);
res.sendStatus(200);
} else {
console.log(error);
}
})
This returns status code 500 for some reason, it's sending the data wrongly and hence why the server error...
Using https
var options = {
url: 'https://api.lendingclub.com/api/investor/v1/accounts/' + accountNumber + '/trades/buy/',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': apiKey
}
};
var data = JSON.stringify(req.body);
var req = https.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
console.log(`HEADERS: ${JSON.stringify(res.headers)}`);
res.setEncoding('utf8');
res.on('data', (chunk) => {
console.log(`BODY: ${chunk}`);
});
res.on('end', () => {
console.log('No more data in response.');
});
});
req.on('error', (e) => {
console.log(`problem with request: ${e.message}`);
});
req.write(data);
req.end();
Https attempt return a 301 status for some reasons...
Using the same data, headers and the url in Postman returns a successful response 200 with the data i need...
I don't understand how i can make a simple http request...
Please note: this is my first project working with nodejs and angular, i would know how to implement something like this in php or java easily, but this is boggling me..
So after a lot of messing around and trying different things i have finally found the solution that performs well and does exactly what i need without over complicating things:
Using the module called request-promise is what did the trick. Here's the code that i used for it:
const request = require('request-promise');
const options = {
method: 'POST',
uri: 'https://requestedAPIsource.com/api',
body: req.body,
json: true,
headers: {
'Content-Type': 'application/json',
'Authorization': 'bwejjr33333333333'
}
}
request(options).then(function (response){
res.status(200).json(response);
})
.catch(function (err) {
console.log(err);
})

Resources