get json from electron BrowserWindow - node.js

I am trying to create a login for my app using discord's Oauth2 currently I am displaying a separate BrowserWindow for the API call since discords Oauth2 requires that the user clicks authorize. my API call returns the raw JSON of the acess_tokens. In my app's current state the separate window only displays the JSON. I need a way to get the JSON from within the window or from the request in a variable. I can't seem to find any way to access the raw content.
function createAuthWindow(){
var authWindow = new BrowserWindow({
width: 400,
height: 600,
show: false,
'node-integration': false,
'web-security': false,
icon: getFile('f','/src/asset/instance.png'),
});
// This is just an example url - follow the guide for whatever service you are using
var authUrl = 'http://localhost:3001/api/discord/login'
authWindow.loadURL(authUrl, (res) => {
console.log(res)
console.log(authWindow);
});
authWindow.show();
// 'will-navigate' is an event emitted when the window.location changes
// newUrl should contain the tokens you need
authWindow.webContents.on('will-navigate', function (event, newUrl) {
// More complex code to handle tokens goes here
console.log(event.code);
authWindow.webContents.session.webRequest.onCompleted({ urls: [newUrl] }, (details) => {
// Access request headers via details.requestHeaders
// Access response headers via details.responseHeaders
console.log(authWindow.webContents.code)
});
});

Sounds like your auth URL is not correct, and that you should be sending an Authorization Code Flow message, so that you can get tokens back to your app.
The usual technique for a desktop app is to:
Format the Authorization Redirect URL
Open this URL in the System Browser, which will handle redirects for you
Receive the response via a Private URI Scheme or Loopback Notification
Swap the authorization code for tokens, which your app can then use to call APIs
The redirect URL will be a value something like this, though I have not used Discord as a provider, so this may not be 100% right:
https://login.discord.com/oauth2/v2.0/authorize?
client_id=y792f434f
&response_type=code
&redirect_uri=com.mycompany.myapp:/callback
&scope=...
&state=...
&code_challenge=...
&code_challenge_method=S256
If it helps I have a couple of blog posts on OAuth for Electron Desktop Apps. It is a tricky flow to implement though ...
Initial Desktop Code Sample
Final Desktop Code Sample

Related

Unable to request click.manage or click.send scopes in Docusign click API

I'm attempting to authenticate a call to Docusign's Click API using the Node SDK. I'm importing the ApiClient through the docusign-click as import { ApiClient } from 'docusign-click';.
My API setup looks like this:
this.apiClient = new ApiClient({
basePath: this.configService.get('DOCUSIGN_CLICKWRAP_BASE_PATH'),
oAuthBasePath: '',
});
and I'm requesting a JWT like this:
const response = await this.apiClient.requestJWTUserToken(
this.configService.get('DOCUSIGN_INTEGRATOR_KEY'),
this.configService.get('DOCUSIGN_USER_ID'),
['click.manage'],
Buffer.from(
this.configService
.get<string>('DOCUSIGN_PRIVATE_KEY')
.replace(/\\n/g, '\n'),
),
30,
);
When I try to request a JWT this way, I get Error: Bad Request. However, when I replace ['click.manage'] with ['signature'] the JWT is generated, so I know the rest of the call is fine.
Is there something else I need to do to allow me to request a click API scope and call to the click API?
Your consent request should also include click.manage and click.send. These are two separate things.
To get consent you need to build a URL that looks like this:
https://account-d.docusign.com/oauth/auth?redirect_uri=[Redirect URL in IK]&scope=click.manage%20click.send&client_id=[YOUR IK]&response_type=code
And simply go to this URL in the browser.
Then make the request for JWT again and it should work.

Trying to use oauth flow in Electron desktop app (with spotify API)?

I have a React app in Electron, and I'm trying to access the spotify API using the spotify-web-api-node library. However, I'm not sure exactly how the oauth flow is meant to work inside of an Electron app... Firstly, for the redirect URL, I used this question and added a registerFileProtocol call to my file. Then I added a specific ipcMain.on handler for receiving the spotify login call from a page, which I've confirmed works with console logs. However, when I get to actually calling the authorizeURL, nothing happens?
This is part of my main.js:
app.whenReady().then(() => {
...
protocol.registerFileProtocol(
"oauthdesktop",
(request, callback) => {
console.log("oauthdesktop stuff: ", request, callback);
//parse authorization code from request
},
(error) => {
if (error) console.error("Failed to register protocol");
}
);
});
ipcMain.on("spotify-login", (e, arg) => {
const credentials = {
clientId: arg.spotifyClientId,
clientSecret: arg.spotifySecret,
redirectUri: "oauthdesktop://test",
};
const spotifyApi = new SpotifyWebApi(credentials);
console.log("spapi: ", spotifyApi);
const authorizeURL = spotifyApi.createAuthorizeURL(
["user-read-recently-played", "playlist-modify-private"],
"waffles"
);
console.log("spurl: ", authorizeURL);
axios.get(authorizeURL);
}
I'd expect the typical spotify login page popup to show up, but that doesn't happen. I'd also expect (possibly) the registerFileProtocol callback to log something, but it doesn't. What am I meant to be doing here? The authorization guide specifically mentions doing a GET request on the auth url, which is what I'm doing here...
In a desktop app it is recommended to open the system browser, and the Spotify login page will render there, as part of creating a promise. The opener library can be used to invoke the browser.
When the user has finished logging in, the technique is to receive the response via a Private URI Scheme / File Protocol, then to resolve the promise, get an authorization code, then swap it for tokens. It is tricky though.
RESOURCES OF MINE
I have some blog posts on this, which you may be able to borrow some ideas from, and a couple of code samples you can run on your PC:
Initial Desktop Sample
Final Desktop Sample
The second of these is a React app and uses a Private URI scheme, so is fairly similar to yours. I use the AppAuth-JS library and not Spotify though.

How to authorize for Amazon's Alexa API?

I want to send a request to this Amazon Alexa API.
That page contains the last 50 activities I made with my Amazon Echo. The page returns JSON. Before you can request that page, you need to authorize your account, so the proper cookies are set in your browser.
If I do something simple as:
const rp = require("request-promise");
const options = {
method: "GET",
uri: "https://alexa.amazon.com/api/activities?startTime=&size=50&offset=-1",
json: true
};
rp(options).then(function(data) {
console.log(data);
}).catch(function(err) {
console.log(err);
});
I can send a GET request to that URL. This works fine, except Amazon has no idea it's me who's sending the request, because I haven't authorized my NodeJS application.
I've successfully copied ~10 cookies from my regular browser into an incognito tab and authorized that way, so I know copying the cookies will work. After adding them all using tough-cookie, it didn't work, unfortunately. I still got redirected to the signin page (according to the error response).
How do I authorize for this API, so I can send my requests?
I have been looking for a solution for this too. The best idea I have is to use account linking, but I haven't try it yet. Looks like ASK-CLI has interface for this also, but I can't figure it out how to use it (what is that URL?). For linking account to 3rd party server is not easy, but link it back to Amazon for the json API should not be that complicated.

Using Hapijs and Bell with twitter provider. How to handle the authorize rejection from Twitter using the Bell module?

I'm using the Hapi framework (nodejs) with the Bell module, working with the Twitter provider.
It was pretty simple to get a working code with the example given in the github page. I access the /login route and I get redirected to Twitter, where I authorize the app and then I'm redirected back to /login?oauth_token=xxxxxxx&oauth_verifier=xxxxxxx where I can have access to the user profile in the request.auth.credentials.
The problem came when I tried to reject the app. Instead of clicking the "Sign In" button on Twitter, I clicked the "Cancel" button and then the "Return to site name" button. This last button redirects me to /login?denied=xxxxxx and then I'm redirected (again) to Twitter to approve the app.
I tried to handle this scenario using another example in the same page https://github.com/hapijs/bell#handling-errors but can't get it to work.
server.route({
method: ['GET', 'POST'],
path: '/login',
config: {
auth: {
strategy: 'twitter',
mode: 'try'
},
handler: function (request, reply) {
if (!request.auth.isAuthenticated) {
return reply('Authentication failed due to: ' + request.auth.error.message);
}
return reply.redirect('/home');
}
}
});
It seems that before checking the request.auth it interprets the /login route and redirects to Twitter. I still don't understand very well the Bell module but it might be that the Twitter strategy is expecting the oauth_token and oauth_verifier in the request.params, but the denied param is not interpreted by the strategy and that's why the redirect happens.
Has somebody managed to handle this scenario?
I found a workaround. It's not an optimal solution but at least allows me to handle the rejection from Twitter.
I had to modify a file inside the bell module. In bell/lib/oauth.js, before the verification of oauth_token
exports.v1 = function (settings) {
var client = new internals.Client(settings);
return function (request, reply) {
var cookie = settings.cookie;
var name = settings.name;
// Sign-in Initialization
// Verify if app (Twitter) was rejected
if (name=='twitter' && request.query.denied) {
return reply(Boom.internal('App was rejected'));
}
if (!request.query.oauth_token) {
// Obtain temporary OAuth credentials
var oauth_callback = request.server.location(request.path, request);
With that change I can catch and show the auth error in the handler, without the automatic redirect.
At least this is the way I managed to make it work. The cons of this modification is that if the bell module is updated then the modification is lost and the bug arise again, unless the updated module comes already with a fix for this. So, you have to keep an eye on that.
Here's the link off the Github issue I created on the Bell repository regarding this bug.

redirect to another app with session token (jwt) in AngularJS and NodeJS

I have a startup module in angularjs. This module is just to login and have public information (login, prices, newsletter...). I have many roles and for each role, i have an app (angular module). I made this architecture because i have complex module for each role and it was impossible to put all roles in one module.
So, for login, i use jsonwebtoken in node like this :
var token = jwt.sign(user, config.secureToken, { expiresInMinutes: 20*5});
res.json({ token: token, user: user });
It works perfectly. I can login into my app. After that, i have to propose a list of roles to redirect to the right module.
In angular, I have AuthHttp service that adds security headers (with token) to call rest service with $http.
How can i redirect to 'mydomain:port/anotherModule' with $location or $http ?
With this code in nodejs :
app.get('/secondModule', expressJwt({secret: config.secureToken}), function (req, res) {
res.render('restricted/secondModule/index.html');
});
NodeJs sends an html code in response and does'nt redirect...
And if i do this in my angular controller :
location.href = route;
i have this result on nodejs console :
Error: No Authorization header was found
I am not sure about the libraries you are using, but issue seems that you are loosing the token because you navigate to a altogether new page.
Based on your auth library you need to pass the token that you get after auth from one page to another.
The options here are to either use browser sessionStorage or querystring to pass the token along and at it back to the http header collection on the new page (module)
This is an old post but I recently took a long time to figure this out. I may be wrong but I believe nodeJS/expressJS can't read the token from the session storage. I believe you will need to pass the token via the request header using AngularJS.
This depends on the front end that you are using. For me, I am using AngularJS and I have to do something like this.
angular.module('AngularApp').factory('authFactory',
function($window){ //the window object will be able to access the token
var auth = {};
auth.saveToken = function(token){
$window.localStorage['token_name'] = token; //saving the token
}
auth.getToken = function(){
return $window.localStorage['token_name']; //retrieving the token
}
return auth;
}
.service('authInterceptor, function(authFactory){
return { headers: {Authorization: 'Bearer "+ authFactory.getToken()}
} //the last line gets the retrieved token and put it in req.header
Then, you just need to include 'authInterceptor' in all the http methods when you communicate with the backend. This way, nodeJS will be able to pick up the token.
You can see the Authorization field in req.header if you use the chrome developer tool and look at the Network tab. Hope this helps.

Resources