I'm completely new to OAuth, and have a workflow question. I'm using node/express/passport, and have successfully set up the app to redirect when requesting my /auth/google endpoint.
However, I consistently get routed to the Google permissions page where I have to offer my application access to my information. What is the mechanism by which I could log in/out without providing that access every time? Essentially, how do I let users log in without requesting permissions again, but still let them log in through Google?
The typical flow is to have your users log in on Google, like you're doing. Once they confirm your application's requested scopes, Google can provide your server with an authorization code which can be traded for an access / refresh token to be stored and used in the future.
Passport should abstract a lot of the back and forth away from you, though. Are you utilizing this library? And if so, are you storing the access and refresh tokens in your own local database for re-use (or at least the refresh token, so you can get a new valid access token when you need it)?
Related
When consenting as a user to delegated permissions an app requests in the Azure portal, I always find a note in the top, saying "Maintain access to data you have given it access to", like:
What I do not understand is the phrase:
"Allows the app to see and update the data you gave it access to, even when you are not currently using the app"
How do I understand this? I thought that after I consent to this, the app can get an access token for the requested data, but only for the lifetime of this access token.
When I never use the app again, the app wont have another valid access token, therefore cannot access my data, right?
But why should the app use my data, when I am not using it?
For application permissions I would understand the phrase... but in this case it does not make a lot sense.
It means the app also gets a refresh token that it can use to get new access tokens when needed.
They are a feature of OAuth.
Refresh tokens can be revoked for various reasons, as this documentation shows: https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens#token-revocation.
If they did not exist, the app would have to redirect you to authenticate again every hour.
We have used refresh tokens to build background synchronization processes for example.
I want to create a Lambda function that uses the Google Tasks API to add tasks every evening at a certain time.
I am unsure of how to authenticate with my account and be able to store access tokens / credentials securely in my lambda environment variables.
As I understand it since my lambda is making a request on behalf of a user (which will always be me in this case) it seems like everything in the docs points to needing to use OAuth2.0 to authenticate which makes sense since you'd want the user's permission to make changes in their account. However since I only want to do so on my account, I wanted to know if there was a way to simply authorize my account without doing a OAuth flow which I don't believe is possible from a lambda since I won't be responding to it every time it runs.
How would I authenticate my application so I can make calls to the tasks API and be authenticated against my account?
This is surprisingly more work than I'd imagined and unfortunately google doesn't generate developer tokens which would have solved a lot of this problem.
Authorization & Consent
There are no immediate ways of authorizing your account for the app that you've created without going through the consent flow. Some cloud service providers generate a developer token for testing your app with your credentials - but google doesn't seem to have this functionality. Not for the Tasks API anyways. AdWords API talks about a developer token but I'm not sure if it's the same concept.
You won't have to re-authorize once you've given consent. This general principal applies to other OAuth using parties, unless the level of consent changes (example: the app starts asking for write permissions in addition to previously consented read) you won't get re-prompted. If permission levels change, you'll get re-prompted.
Now - the second part - how do you make one?
Google explains it in detail here - but I'll further simplify because you don't need to setup a web-server for your case, you're only doing this for yourself.
Our goal is to only to get you the initial refresh token. Once you've retrieved the refresh token, you can use that from your Lambda to retrieve a new access + refresh token whenever you're accessing the tasks API. You just need to keep the refresh token stored somewhere, so you can continuously keep on accessing the tasks API. You're just looking to get the access + refresh token.
Head over to https://console.developers.google.com and create a new application.
After the creation, click 'Enable APIs and Services' and look for Tasks API.
Proceed with creating the credentials and make sure you select you'll be calling this API from a Web Server. Selecting Browser (JavaScript) would only give you an access token and not a refresh token, because they would trust you to store the refresh token on your server, but not on a browser. An access token is time-limited to (conventionally) 60 minutes.
You should also select the User Data / Information and not the App Data / Information for the types of data you want to access. The app one is generally used for GSuite.
Set your redirect uri to be http://localhost:8080 - This is where you normally would need a web-server but we'll just redirect back to your machine and get the parameter from here. It obviously won't find a web-server but the parameter we want is in the url, we'll just copy it.
Now here comes the authentication part. Google's auth url is: https://accounts.google.com/o/oauth2/v2/auth
We will add parameters to this url
access_type=offline // so your daemon app can access it offline
response_type=code // required if you have access_type=offline
scope=https://www.googleapis.com/auth/tasks // what do you want to access to
redirect_uri=http://localhost:8080 // where would google send the code
client_id=
so the whole thing should look like https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&response_type=code&scope=https://www.googleapis.com/auth/tasks&redirect_uri=http://localhost:8080&client_id=
Go to this URL and you should get prompted for consent.
Consent to it and google should redirect you to http://localhost:8080/?code= We'll need that code. That needs to be sent to google to get an access + refresh token.
Code exchange: Make a post request to Google. You can use PostMan. Again normally all of this would be automatically handled by a webserver (detect code parameter, make post request etc..) - but we just need the refresh token here, so we can stick that into our Lambda app.
POST to:
https://www.googleapis.com/oauth2/v4/token
with parameters:
code=<the code you've retrieved>
client_id=<your_client_id>&
client_secret=<your_client_secret>&
redirect_uri=http://localhost:8080&
grant_type=authorization_code
Google should return you the access token and the refresh token. From this point on you need to save the refresh token into your Lambda app - and if it's running on a scheduled job on every bootup:
Read the refresh token
Call Google for a new refresh token + access token
Save the new refresh token.
Use the access token to access your Tasks API.
I am making an app that returns a music playlist based on a user’s age. The user does not need need to log in to their account; they only need to provide their age. I also have no need for a database, so I decided that I want to make the application front-end only.
In order to make requests to Spotify’s API, I need an access token which I get via client credentials, because the user doesn't need to login using that flow. However, the script I used to get the access token must be run from the server-side, which I discovered here: Access-Control-Allow-Origin denied spotify api.
The alternative solution is to use the implicit grant flow, which will allow the script to be run client-side but will require a user to log in. So, both the client-credentials and implicit grant flow don't solve my problem.
How can my web app get an access token so that I don't need to implement a server-side or have the user log in?
Although the idea is different, I want to do something like this person is doing # http://sixdegreesofkanyewest.com/. No one logs in, yet he is able to get an access token and send api requests on their behalf. And I don't really see why that website would require a database either.
If I do end up having to develop a back-end, then I would be able to use client-credential flow. But, how would my back-end send the access token to my front-end without a DB?
Any help is appreciated. Thank you!
Implicit grant is recommended for javascript based application, who can not keep secrets safe. So you may have to strike out this option.
Having a server page, (hope the credentials kept safe in your server), then server app sending the request for token and rendering the page..
I guess that is what the http://sixdegreesofkanyewest.com/ will be doing.
So your option is server pages application. or an intermediate API call to get the access token for you and continue your application logics
I'm creating a node.js application that will update playlists (owned by an account in which I have credentials) daily. According to the Spotify documentation, to add tracks to a playlist (https://developer.spotify.com/web-api/add-tracks-to-playlist/), authorization must be supplied using oauth2.
I'm struggling to find a way to do this completely server side with no redirects/etc. It seems like if I can get a refresh token, I can just use that?
I've been looking at the spotify web api node module (https://github.com/thelinmichael/spotify-web-api-node), oauth.io, and the spotify api.
Any ideas would be appreciated! There is only one account that will have to be authenticated, so it could be hard-coded at least for now.
You've picked the correct authorization flow - Authorization Code, since you need an access token that's connected to the user who owns the playlists you're updating. This of course also gives you the ability to refresh the token whenever you need to. (The expiration time is one hour, but you don't need to refresh the access token until your application actually needs to use it.)
As a sidenote, the Client Credentials flow is meant for server to server communication that doesn't require a user's permission, e.g. to search, read a playlist, or retrieve new releases. The Implicit Grant flow is meant to be used in frontends, and doesn't allow you to refresh the token.
I'm struggling to find a way to do this completely server side with no redirects/etc. It seems like if I can get a refresh token, I can just use that?
Once you have the refresh token you can continue to use it to retrieve new access tokens, which can be done without any user interaction. You need to do some preparation work to retrieve the refresh token though.
Following the steps describing the Authorization Code flow, you first need to direct the playlist's owner to a URL on Spotify's account server.
The documentation contains the following example URL:
GET https://accounts.spotify.com/authorize/?client_id=5fe01282e44241328a84e7c5cc169165&response_type=code&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback&scope=user-read-private%20user-read-email&state=34fFs29kd09
Simply replace the client_id and redirect_uri with your application's information. Also modify the scope parameter to match the scopes you need, which from my understanding of your use case is playlist-read-private,playlist-modify-private,playlist-read-collaborative since you want to be able to read and modify all of the user's playlists. Supplying state is not required.
Using spotify-web-api-node you can generate this URL using the createAuthorizeURL method, but since you're only doing this once it's unnecessary to write code for it.
Instead, simply open the URL in your browser.
If done successfully, you'll be taken through a little login dance where your application asks for your permission to read and modify your playlists. When this is completed, Spotify's account service will redirect the browser to your redirect_uri URL with a code query parameter included as described in step 3 in the Authorization Guide.
However, since you're only doing this once, it would be enough to start a webserver on your own machine, set your application's redirect_uri to your localhost, and complete the login flow. Have a look at web-api-auth-examples for a ready-made node.js application that fires up an express server and reads the authorization code.
Once you've got the code, you can trade it for an access token using cURL as it's done in step #4 in the Authorization Guide, or use the code in the web-api-auth-examples repository.
Finally, with the tokens retrieved (step #5), you can start to use the Web API with the access token, and get a new one when it expires using the request in step #7.
spotify-web-api-node has a helper method to refresh the token. Search the main documentation for the refreshAccessToken method.
This use case is slightly mentioned in the FAQ section of the Authorization Guide.
As you said, you need to obtain a refresh token using the authorization code flow. For that you will need to carry out the OAuth process using your user account, the client_id of the app you have registered, and the scopes you need (it will vary depending on whether the playlist is private or public). Then, take the refresh token you have obtained and the client secret key of your app, and you can obtain access tokens without the need of the login form.
This related StackOverflow question might help too Spotify automated playlist management with PHP back-end and rate limits
When I call an oauth provider like gmail and I get the token back, how can I make sure that all future calls I make are from that same client that did the authentication? that is, is there some kind of security token I should pass pack? Do I pass that token back everytime?
For example, if I have a simple data table used for a guest book with first,last,birthdate,id. How can I make sure that the user who "owns" that record is the only one who can update it. Also, how can I make sure that the only person who can see their own birthday is the person who auth'd in.
sorry for the confusing question, I'm having trouble understanding how azure mobile services (form an html client) is going to be secure in any way.
I recently tried to figure this out as well, and here's how I understand it (with maybe a little too much detail), using the canonical ToDoList application with server authentication enabled for Google:
When you outsource authentication to Google in this case, you're doing a standard OAuth 2.0 authorization code grant flow. You register your app with Google, get a client ID and secret, which you then register with AMS for your app. Fast forwarding to when you click "log in" on your HTML ToDoList app: AMS requests an authorization code on your app's behalf by providing info about it (client ID and secret), which ultimately results in a account chooser/login screen for Google. After you select the account and log in successfully, Google redirects to your AMS app's URL with the authorization code appended as a query string parameter. AMS then redeems this authorization code for an access token from Google on your application's behalf, creates a new user object (shown below), and returns this to your app:
"userId":"Google:11223344556677889900"
"authenticationToken":"eyJhbGciOiJb ... GjNzw"
These properties are returned after the Login function is called, wrapped in a User object. The authenticationToken can be used to make authenticated calls to AMS by appending it in the X-ZUMO-AUTH header of the request, at least until it expires.
In terms of security, all of the above happens under HTTPS, the token applies only to the currently signed-in user, and the token expires at a predetermined time (I don't know how long).
Addressing your theoretical example, if your table's permissions has been configured to only allow authenticated users, you can further lock things down by writing logic to store and check the userId property when displaying a birthday. See the reference docs for the User object for more info.