I am trying to build an application where a user can specify a URL for a website and my page will go to that URL and grab information. If the URL requires user authentication to access the information, then I want to use OAuth 1.0 to be able to do that.
The problem is, and I see this skimped over in OAuth tutorials, as far as I can tell my application has to already, somehow, be registered with the page I am requesting information from. My understanding is that for any page I want my users to be able to use, I have to go to the page individually by myself and register my application. Once that's done, it will give me a consumer key and secret that I hardcode into my page, and then use those when I am accessing the request URL, authorization URL, and access URL. This is, of course, no good for me because I want my users to be able to specify arbitrary pages to access information on and then provide their credentials to those pages in order to give my app access to the information on them.
Additionally, from what I can tell, there are three URLs that I need to know:
The request URL, which I send my consumer key/secret pair to in order to receive a new, unauthorized request token.
The authorization URL, which I direct the user to with query arguments for the request token and the oauth_callback. The user will be redirected out of my webpage, log in to the foreign site, grant me access, and then be redirected back to the URL specified in oauth_callback with information regarding whether or not they authorized my request.
The access URL, which I send the authorized request token to, expecting to get an access token in return.
And then, once I have all those, I can use the access key/secret pair as a username and password. I store them in a cookie related to the user, and use them henceforth whenever I am access information on the website. On the website's end of the deal, it will look for that information in my request, and if I include it properly then I will be allowed to access whatever of the user's data I please.
Is what I am trying to do - give generic OAuth access to websites - possible, or is it required that I, as the application owner, register my application with the server in order to get OAuth access to it? If it is possible, then how do I get that request URL, authorization URL, and access URL?
It's not really possible. Here's the short list of problems you will encounter:
You need to have application tokens (e.g. your application registered with the resource owner) for all websites. It's not something you can do on the fly
Inconsistent OAuth URL schemes from different resource owners. Twitter has a different URL structure for OAuth than Google does which is different than Foursquare. It's not really possible to figure out the URLs without hardcoding it
Scopes. When you do OAuth registration for many resource owners, you need to specify a scope. How will you know what the scope should be
Related
I'm new to OAuth2 and I'm trying to understand the whole flow of things. For context, I'm thinking of making a web dashboard where users log in via Discord's OAuth2 API.
This is how I think the flow works based on my understanding so far:
User goes to my site and clicks a login link
My site redirects them to Discord with my client ID and a redirect URL #1 in the query string
Discord redirects them back to my site at redirect URL #1 with an authorisation code in the query string
My site takes this authorisation code and along with my client ID, client secret and redirect URL #2, uses all these to fetch an access token and refresh token from Discord
If I do get an access token, that means the user is now "logged in" (authorisation code worked)
My site finally redirects the user to a page and is now free to send requests to Discord's API with the access token, while saving the access token and refresh token. Just for example, say the page states their Discord username
I'm learning from this guide, and what confuses me is this code snippet from the guide. At line 5, it provides the redirect URL #2 mentioned above, in the query string. I'm not sure what it's for.
Also, I'm not very sure how to continue once I have the access token. If multiple users log in, I'd have multiple access tokens on hand. Say a user wants to access the page again, how do I uniquely identify them and know which access token to use to send requests to Discord's API? (for this example, the request would give me their username which I'd display on the page)
Yeah, I probably got a lot of concepts wrong. Any clarification would be greatly appreciated!
Edit: I've done more research into this, and found a much better guide here.
For my question about the second redirect URL, the examples in the official documentation specify a redirect_uri when doing both an access token and a refresh token exchange. However, this new guide makes do without for their access token exchange. Perhaps they missed it out? As this other stack overflow question says:
As an added measure of security, the server should verify that the redirect URL in this request matches exactly the redirect URL that was included in the initial authorization request for this authorization code. If the redirect URL does not match, the server rejects the request with an error.
I suppose this means that after the first access token exchange, any refresh token exchanges or straight up API requests with access tokens need to match the original redirect_uri of said first access token exchange. So I should use one and only one redirect_uri, and the refresh token exchanges/API requests do not actually use the redirect_uri, rather it's used for further security.
As for the whole login procedure, it seems I have to link the access & refresh tokens I obtain to a user session, and for that I'll look into using this passport strategy, passport-discord. Then, once the session expires, I'll discard the two tokens, and they'll have to click login again, but I can make use of this prompt option:
prompt controls how the authorization flow handles existing authorizations. If a user has previously authorized your application with the requested scopes and prompt is set to consent, it will request them to reapprove their authorisation. If set to none, it will skip the authorization screen and redirect them back to your redirect URI without requesting their authorization.
From there I think I'd just store the new access and refresh tokens associated with that user.
I'd really appreciate if any mistakes in my thought process could be pointed out!
Your summary seems good to me Mr Cloud - worth clarifying whether you are developing an SPA or (old) web app with a server side. Most commonly the first is cookieless, whereas the second stores a refresh token in a cookie. A key thing is to understand what the OAuth message workflow looks like. For SPAs and APIs this write up of mine may help you clarify what you want: https://authguidance.com/2017/09/26/basicspa-oauthworkflow/
Happy to answer any follow on questions ..
You can use the implicit grant to use with SPA
https://discord.com/developers/docs/topics/oauth2#implicit-grant
New to Oauth and had a general question. Is there a way to restrict who can log into your site with Oauth 2? Similar to AD groups or something so I could control who I want to be able to log in based on group or user name? I would like people to use google or facebook but only let certain people actually log in.
You can filter users in a code that handles the redirect_uri. If you use the Auth code grant, that will be some backend code and if you use the Implicit flow, it will be a code in a browser application. But the JavaScript security restrictions should have their equivalent somewhere at the backend too, since the JavaScript code can be altered by the browser user.
To be able to do that (to have info about an authenticated user), you should either request an ID token or an access token with a scope that authorizes you to get user info at the /userinfo endpoint.
I'm integrating Dropbox support in my application, and to get an access token to a user's account I use their OAuth2 flow. After the user has granted the application access I need the user to be redirected to the same URL it came from. The problem is that a user may come from any of a number of subdomains, and I don't have full control over these subdomains, which means I can't add them all to the redirect URL list in my Dropbox app settings.
I thought I'd solve this by having a general redirect URL under the www subdomain, which in turn would redirect to the correct URL. However, there doesn't seem to be any way to send custom data that Dropbox will include in the redirect URL. I've expermiented with YouTube's OAuth2 API and they allow you to send custom data in a state query parameter, which it will include when redirecting back. But this does not seem to be allowed for Dropbox. Does anyone know whether there is any way to do this?
Thanks
Dropbox supports the state parameter (up to 500 bytes, see the docs for /1/oauth2/authorize), and you can set arbitrary state in the Python SDK using DropboxOAuth2Flow.start.
When you complete the OAuth flow and call DropboxOAuth2Flow.finish, the state you passed in will be returned as the third member of the tuple.
If Dropbox doesn't honor the state parameter (and violates the spec doing so) the only alternative is to make sure the custom domains redirect to the general domain as well before kicking off authentication towards Dropbox, and then store the custom URL in a cookie that resides on the same general domain as the redirect URL. You can then pickup the state/custom URL from the cookie on return from Dropbox.
I am writing an application which will connect to multiple email servers using OAuth. As part of initial connection establishment, user will be prompted to give access to application. After granting access, it will redirect to the url provided while registering the application in OAuth API.
Now i want to identify for which user the access token and refresh token belongs after redirect url comes to my application. I want to treat all requests happening in one user session as unique. Can someone help me.
I'm not 100% sure I followed your question, but my understanding is that you want to determine some of the information about the user that's just logged into your API client. You can get email addresses by requesting the https://www.googleapis.com/auth/userinfo.email scope and running a oauth2/userinfo GET request:
gapi.client.oauth2.userinfo.get().execute(function(resp,raw)...
Depending on which scopes you have access too, you will also get a display name and some other info. Best bet is just to console.log(resp) and pick out what you want to use.
I'm building an iOS app that will use instagram photos in a slide show as the background of the app.
What I want to do is just set up a specific account that I can upload pictures to, and then the app will pull in the most recent photos from this account.
So far, I've set up the account and have been able to generate an access token manually by inserting my client id and redirect URI into this URL
https://instagram.com/oauth/authorize/?client_id=[CLIENT_ID]&redirect_uri=[REDIRECT_URI]&response_type=code
However, I've read that the access token generated from following this procedure is not permanent. I do not want the users of my app to ever see the authentication going on in the background. They themselves will never actually login into Instagram.
What would be the best way of making sure my app is always authenticated at launch and that the access token is always valid?
Thanks
A typical OAuth flow has the resource owner (a user) approve or deny requests from a client application. When you first got an access token, you had to complete a form approving access to Intsagram by your app.
Since you want to hide the auth_server/resource_owner interaction from your end users, you'll have to automate the role of the resource owner. The access token should tell you when it expires. Since it's your redirection endpoint that has the access token, that's where you'll need code to detect the token will soon expire and request a new one. Your code will need to
Simulate a request from the client app by going to https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=code
Respond to the HTML page that is returned. Approve the request.
The server will respond with an authorization code that you can exchange for
a new access token.
There are some hoops to jump through because OAuth is designed for the resource owner to approve or deny each request.
I don't think you would want to do this by logging into the target account because having your app's user log in to Instagram as the account you are talking about may be unnecessary.
While I am not an expert on the Instagram API, it looks like you can avoid using an access token for getting the feed of a particular user.
Here is some support for this:
Do you need to authenticate?
For the most part, Instagram’s API only requires the use of a client_id. A client_id simply associates your server, script, or program with a specific application. However, some requests require authentication - specifically requests made on behalf of a user. Authenticated requests require an access_token. These tokens are unique to a user and should be stored securely. Access tokens may expire at any time in the future.
http://instagram.com/developer/authentication/
If a client ID is only associated with your application and does not require the user to authenticate, it appears that this endpoint should work:
GET /users/user-id/media/recent
https://api.instagram.com/v1/users/3/media/recent/?client_id=YOUR-CLIENT_ID
The functionality is the same with the previous one, but use client_id
instead of access_token
PARAMETERS
COUNT Count of media to return.
MAX_TIMESTAMP Return media before this UNIX timestamp.
MIN_TIMESTAMP Return media after this UNIX timestamp.
MIN_ID Return media later than this min_id. CLIENT_ID A valid client id.
MAX_ID Return media earlier than this max_id.
http://instagram.com/developer/endpoints/users/#get_users_media_recent_with_client_id