How to use OAuth with Github in a Safari extension - javascript

I'm new to browser extensions. i'm trying to create a Safari extension that allows me to perform basic tasks in my Github account (Create a repo, for example). I'm doing it mostly to learn how to develop extensions while practicing my JS.
The issue is that in order to connect to Github I want to use OAuth, but I have no clue of how to do that. I have googled to see if I can find a library that I can use without any results. The main problem is that when trying to register my "application" with Github, I have no idea of what URL to provide for the main application and the callback, since it is not a web application what I'm developing; it's an extension.
Does anyone have any experience with this and can give me a tip on how to proceed? What URL should I use to register with Github? Is it possible to use OAuth from an extension at all? Is there a library, SDK, anything that can help do this job?
If this question can be broaden to any browser, just tell me and I will change the title to help others in the same situation.
Thanks to all for helping.

I have used OAuth in a Safari extension and you're welcome to look at my code for an example (see link below), but this JS library for Github might have all you need. I haven't used it, but it looks nice, and it supports "personal access tokens", which I take to be a kind of OAuth token for Github that doesn't require specifying a redirect URI.
My Safari extension (Github link) uses OAuth 2.0 to talk to the Pocket API. It doesn't use a library. For the redirect URI, I use the same URL as that of the page that initiates the whole authorization process, but with "?status=done" appended to it. The page's script checks its URL, and if the URL ends in that string, then it knows that the page was loaded by the authorization window and so it can proceed with getting the access token.
One thing you should be mindful of when using OAuth in any kind of client-side application, such as a browser extension, is that your OAuth app token will be exposed to the users of your app. Even if you encrypt it in the app or retrieve it from a server over https, a user can use the browser's built-in JS debugger to get the token, because you have to decrypt it at some point in order to use it. If someone steals your token, they can use to trick people into authorizing their nefarious app that pretends to be yours. It's up to you to decide whether this risk is tolerable. The only way to avoid this risk is to have your own server-side app that communicates with the third-party API, and your extension communicates with that. But then someone could learn from your extension's code how to talk to your server-side app, so I'm not sure whether that really buys you anything.

Related

What redirect URI should I use for an authorization call used in an Electron app?

I have a basic Electron app doing nothing special, based on sample starter projects.
For my main window, I am loading in a URL as a GET request to an API endpoing
loginWindow.loadURL('https://apiwebsite.com/api/v1.0/authorize?secret_id=my_secret&redirect_uri=<???????>')
As a part of my GET request to this API endpoint I have to send a return URI. This actually works fine, in that I can get the API to return and load the URI that I specify. However I do not know what URI to specify to get this to come back to somewhere within my app where I can read the response and proceed.
I am used to web development but Electron is new to me. I do not follow how I can submit a return URI in this instance. What would be it be? Would it change for local development vs a packaged application?
Is there a better way to do this?
OAUTH FOR DESKTOP APPS
OAuth for desktop apps recommends these 2 key behaviours:
Login via the system browser so that your app never sees the user credential
Use Authorization Code Flow (PKCE) since your app is a public client
This typically leads to one of these solutions:
Loopback based redirect URI such as http://127.0.0.1:8000/callback
Private URI scheme based redirect URI such as x-mycompany-desktopapp:/callback
As you are finding, a standard HTTP based internet redirect URL will not work for a desktop app unless you use older (deprecated) web view solutions.
RESOURCES OF MINE
It is tricky flow to implement, though my blog has a couple of Electron code samples that you can easily run from your local PC to see what both solutions look like:
Initial Desktop Code Sample, using the Loopback Solution
Final Desktop Code Sample, using the Private URI Scheme Solution
My samples are quite deep, but hopefully some of this is useful for your own solution ...

HTTPS on localhost for OAuth for a desktop application

I am creating a desktop application that using Spotify's oauth api. I am using the implicit grant flow described here: https://developer.spotify.com/web-api/authorization-guide/#implicit_grant_flow
My idea is to have an "Authenticate" button, that you click and it opens your browser. You login/approve the connection with Spotify. Then it sends you to a redirect url.
I want to set this redirect url to 127.0.0.1:58212 or some port on the loopback device.
My question is, should I use https for this?
I am leaning towards yes. One because the access token needs to be secure, and I believe other users on the system could potentially read the message when it is sent, and two because in the time it took the user to log in, someone could have taken over the port.
So I want SSL for encryption of the message, and I want to ensure I am actually talking to my app.
How do I generate certificates in this situation? I think each instance of the application needs to have its own certificate, and I need to somehow inform the computer to trust that certificate during the lifetime of the application.
I could also generate the certificate during installation, and do some step during installation that makes the system trust that certificate.
Am I thinking about this the correct way, or am I going about this all wrong?
I am using electron and express in JavaScript to write my application.
Thanks for any advice.
The best way to securely use Oauth with installed applications such as desktop applications is to use the Oauth 2 flow for installed applications. But this option would have to be implemented by the service provider. Google provides for this option.
https://developers.google.com/api-client-library/python/auth/installed-app
Unfortunately, many services do not implement OAuth2.
To use Oauth 1.0 with installed applications, instead of returning to a callback_url, the service provider displays the auth code to the user which the user can then copy and paste to the desktop application. Check out Trello Ouath integration which allows for this.
The Web Api flow that you are trying to achieve will not work in the case of desktop apps. The redirect uri 127.0.0.1:port is your local uri. The service provider will need, at the very least, your public ip to redirect the flow back to your system.
AFAIK, for a Desktop or a native app it is much better to implement the Oauth authorization code flow. The implicit grant is intended to be used on a device browser and not on a Web View.
If your app uses a Web Service to connect, your Web Service needs a redirect URL that uses https. Luckily most hosting platforms like Heroku provide this to you for free (otherwise you need to buy an SSL certificate which might be a lot of work).
On the authorization code flow, a token doesn't need to see the client, it is all stored in the backend.
Most services allow you to test on localhost with http.
I wrote a tutorial that could give you some guidance on the flow.

Valid JavaScript API Domain for linkedIn to use in Chrome extension

What should be a better way to specify a valid SDK domain for LinkedIn Oauth while using it in your Chrome extension?
I am trying implement LinkedIn Oauth in my chrome extension and got confused because chrome extension it completely different environment than a simple web application. Don't what should be callbacks functions.
If anyone has done linked Oauth with Chrome extension then please share your experience.
If you're using chrome.identity API to handle OAuth, then you can specify
https://<extension-id>.chromiumapp.org/<anything-here>
as your callback URL. Note that no network request will actually go to that address - it'll be automatically intercepted in your extension. See the Non-Google account authentication guide in the docs.
Note that this potentially involves putting your secret API keys inside the extension. If you want to avoid that, you'll need to set up your own server to handle it for you (and not use chrome.identity).

How it is possible to not expose you secret key with a Javascript OAuth library?

Looking at Twitter OAuth Libraries, I saw this note:
Be cautious when using JavaScript with OAuth. Don't expose your keys.
Then, looking at jsOAuth examples, I noticed that the keys are exposed in the code.
So my question is: How it is possible to not expose your keys when you use an OAuth library in Javascript?
Thanks.
UPDATE: Ok, maybe jsOAuth is not the right library to use, but how it is possible to do authentication with OAuth on a full Javascript web site?
As said in the documentation linked by you:
Written in JavaScript, jsOAuth aims to be a fully featured open source OAuth library for use in Adobe AIR, Appcelerator Titanium and PhoneGAP. In fact, anywhere that javascript can be used and has cross-domain XMLHttpRequests. For security reasons jsOAuth doesn't run in the browser. Browsers are only mentioned here for running the test suite. If you need jsOAuth in the browser, write an extension.
A good answer to your added question is available here:
Secure OAuth in Javascript
The only really reasonable way, right now, to do OAuth 1 in the browser, is to route API-calls via your server.
There simply is no way, as far as I have understood it, around this. If you do OAuth 1.0a calls through JavaScript from the browser -> You will HAVE to expose your consumer secret and access token secret, to at least the end user.
You cannot store these credentials in:
a cookie, the user can find them.
local storage, the user can find them (better than cookie though, since it does not entail sending a cookie back and forth all the time over HTTP)
in javascript, the user can find them (although this is probably your best bet since it is easier to obscure).
If it were only the access token secret that was exposed to the end user, that would be bearable - since it is in fact he/she who have authenticated your application. But losing your consumer secret is really not so hot, it means that your application is eligible for identity theft. I.e someone else could write an app that claims to be your app.
Even if you made it work securely in the browser, you are hampered by cross domain security blocks.
You could also make a script that sends all necessary values and parameters to the server to do the signing with.
The signed URL can then be sent back to the client (browser) that in turn does the actual request.
I have implemented OAuth 1.0a on the Twitter API that way using jsonp requests.
The benefit of this is that the response body is not relayed via your server, saving bandwidth.
That way you can have your cookie and eat it too.

How to alias a URL?

I'm testing client-side Facebook auth locally.
I'm hitting the error
API Error Description: The specified URL is not owned by the application
because I'm testing locally, what is the best way to work around this and alias the URL so I can keep testing locally?
I'm using a Mac.
Thanks!
In the facebook application you can set a URL in the app tab where the script is being executed. This has to be set if you're working on some external website.
Reason why:
If i was to discover the app id of someones app i cannot start posting feeds and whatnot in it's name. You have to be specific with the URL in the application so it will be granted access.
Edit
To my knowledge you cannot work local with facebook applications when it comes to JavaScript. You can specify the local URL in the facebook api but i don't think it will go trough without giving the same error.
Assuming I understand your question correctly, for this I would use Charles Proxy and make use of its Map Remote functionality.
Changing the url on Facebook to localhost works.

Categories