I have a user microservice. This microservice uses token authorization. Now it's consumed by web application. Workflow looks like this:
user logs in to web application using AzureAd OpenIdConnect;
web application receives access token (authorization code flow);
web application gets user details from user service passing access token in HTTP request header.
Also I have a daemon microservice where I don't have a user context. I want to allow this daemon service to get user details from user service too. I'm going to use client credentials flow for that case.
How to organize user service rest api properly?
I'm thinking about this approach:
user's data is available at this URL /users/{userId}/info;
applications with user context (i.e. access token is issued for particular user using authorization code flow) can consume data only for current user or current user is an admin and can work with another user's data;
daemon applications without current user (i.e. access token is issued for the application itself using client credentials flow) can read data for any user.
What is the best practices for such cases?
I think the best and more restful approach to define this API is to build a unique endpoint /users/{id}.
Where id can be an actual real user id or a predefined value like 'me'. It is the user service the one who has to retrieve from the token the user information in case that the id value is 'me'.
The other changes that I would make is to use users instead of user because rest good practices say that the elements in the URL are collection.
And the last one, to not use info because it is redundant. Because when you query for an entity obviously you want its info
Related
I'm building an application where I want to be able to create and authenticate users using Discord and OAuth2. The reasons are:
The application can be considered a "companion" app to a Discord community I am running, and
I don't want the users or myself to have to deal with usernames and passwords
The application consists of a client desktop application and backend services. I have a fairly basic understanding on how I authorize the user with Discord:
Client application goes to backend endpoint /oauth/login and the user is redirected to the Discord app approval page
The user confirms and is redirected to the backend callback /oauth/callback with a code that can be used to fetch a pair of access and refresh tokens.
Frankly, from this point I am kind of stumped on how the rest of the authentication should work. I assume at least the following:
I need to create a user entry in my database with at least an UID (for simplicity the same as the one for the user in Discord), the access and refresh token pair. If user is already created, update the database with the new tokens.
Whenever the application needs user information from Discord it should use the access token. If it has expired, exchange the refresh token with Discord to get a new token pair.
But now what? This only authenticates the user against Discord. I want to leverage the fact that the user is authenticated with Discord to be authenticated to my application. Here are some general questions I have:
Do I make a new token for the user to use for subsequent requests to my backend endpoints? Or do I return the Discord access token to the desktop client?
What do I do when the token expires? Do I also need a "exchange" endpoint for the desktop client to refresh the token (possibly that just forwards to Discord to get a new token, depending on the answer to my previous question).
This all feels like it should be very basic, but I am out of my comfort zone here and need some help to be unblocked.
Thanks for reading!
Your own application should effectively have its own session system.
The easiest is likely to just use HttpOnly cookie-based sessions, which something like a Redis store (or Memory store if this is a toy project).
The session data on the server should contain information on which user is currently logged in. You should probably store the discord access and refresh token in a database.
The simplest way to deal with refreshing, is to simply call their refresh token endpoint as soon as you get a 401 response. If discord provides information on how long access tokens are valid, you could also preemptively refresh instead of only doing this when you get the 401. Your server does the refreshing, you don't need an endpoint for this.
Generally I can recommend that your server handles all interactions with the discord API, and never your client. (aside from the initial authorization step).
I am creating a rest api to be the backend for a messaging app. I want a user to only have access to their own data. For example user1 can call /users/user1 but not /users/user2. How would I go about doing this.
So first the user will login and be authenticated via their username and password. But where do I go from here? I was thinking of storing a token with the users data so when they access it I can verify that the pair matches but there must be a better way to do this. Do I need to restructure my api?
After the user logs into the system, you should provide them a token or initialize a session for that user. In each consecutive call, the user should send the token to the API. As long as the token/session is alive user should be able to call the API.
You should have a way to verify the user token in the backend for each API call. A very popular way of doing this is to use JWT(JSON Web Tokens) based authentication.
See here for an example using python and flask: https://realpython.com/token-based-authentication-with-flask/
Once you verify the user, you should parse the user id to the database query in order to filter out the data for that user.
Even though I don't understand your full use case, it seems like you need to restructure your API calls as well. You should not provide API calls per user. What happens when the numbers of users increase in your system dynamically?
So you should either accept user id as a parameter or you should let the JWT authenticator take care of it.
Example REST API call would be
GET /user/data?userId=1234
TL;DR When using google oauth on desktop app, what to save on disk to avoid repeated sign in? Save the google user id? or the token? or an session id?
I'm creating an little desktop app, whitch must authenticate to my REST API server. I'm using google oauth2 for that.
The idea is, that when the desktop app will be authentivated, it generates some data that will be send to my server. The server will store the data with the google user id received from https://www.googleapis.com/userinfo/v2/me.
On the first run of the desktop app, it will open the default browser, with and url for my server and start an local http server. then:
my server will redirect the browser to google (with the clientid, secret, etc.)
user logs in and it will be redirected back to the server with the oauth code
server uses the code to get the token, and then the user profile and stores the token and the profile in db, then redirects the browser to localhost with an paramerer
the desktop app catches the parameter and stores it in an file on the disk
next time the desktop app will start it only reads the file for the parameter to send the generated data with it to my server
my question is: what the parameter should be? the google user id? the oauth token? an generated session id for this desktop app? or something else?
when it will be the google user id, it can conveniently sent the data with the user id and the rest server will just store it in db as is. but I don't think it's safe
when it will be the token, the rest server has to with every request also get the user profile from google with the token. and imho sending the token with every request isn't safe either
generating an session id means to store it with the user and the token on the server and the desktop app will just store it and send it with every request. but I don't know if it's safe to do that
As it's normally the case in software development you have a couple of options depending on requirements.
The mandatory requirement is that your client (desktop) application needs to send something to your REST API so that the API can perform up to two decisions:
Decide who the user is.
Decide if the user is authorized to perform the currently requested action.
The second step may not be applicable if all authenticated users have access to exactly the same set of actions so I'll cover both scenarios.
Also note that, for the first step, sending the Google user ID is not a valid option as that information can be obtained by other parties and does not ensure that the user did authenticate to use your application.
Option 1 - Authentication without fine-grained authorization
Either always sending the id_token or exchanging that token with your custom session identifier both meet the previous requirement, because the id_token contains an audience that clearly indicates the user authenticated to use your application and the session identifier is generated by your application so it can also ensure that. The requests to your API need to use HTTPS, otherwise it will be too easy for the token or session ID to be captured by an attacker.
If you go with the id_token alternative you need to take in consideration that the token will expire; for this, a few options again:
repeat the authentication process another time; if the user still has a session it will indeed be quicker, but you still have to open a browser, local server and repeat the whole steps.
request offline_access when doing the first authentication.
With the last option you should get a refresh token that would allow for your application to have a way to identify the user even after the first id_token expires. I say should, because Google seems to do things a bit different than the specification, for example, the way to obtain the refresh token is by providing access_type=offline instead of the offline_access from OpenID Connect.
Personally, I would go with the session identifier as you'll have more control over lifetime and it may also be simpler.
Option 2 - Authentication + fine-grained authorization
If you need a fine-grained authorization system for your REST API then the best approach would be to authenticate your users with Google, but then have an OAuth 2.0 compliant authorization server that would issue access tokens specific for your API.
For the authorization server implementation, you could either:
Implement it yourself or leverage open source components
⤷ may be time consuming, complex and mitigation of security risks would all fall on you
Use a third-party OAuth 2.0 as a servive authorization provider like Auth0
⤷ easy to get started, depending on amount of usage (the free plan on Auth0 goes up to 7000 users) it will cost you money instead of time
Disclosure: I work at Auth0.
There should be no problem sending the access_token with every request since they are created for that purpose and are thus short lived. You can use the Google Authorization Server endpoint to verify a token instead of using it to do a request for a users profile.
If you're only relying on Google for authentication, here's how your workflow can look:
the client (desktop application, in your case) retrieves the
Google id_token following the user's log in, and then sends it to
the server
the server validates the integrity of said token and extracts the user's profile data; this could mean a simple GET on Google's endpoint to verify this token: https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
On subsequent requests, nothing should change really, except that the user's login process will be automated (since he's given permissions & all), and thus much faster. #danielx is right, there's no problem with sending the token each and every time.
I am using a REST in Java and also I am using a token system for that. I need to know that, how we need to maintain the user session? Since REST is stateless we can not maintain user session, then how we need to find the active user in server side?
After user is authorized and given access to the REST API a kind of a token or cookie should be returned with authorization response. The obtained token should be added all subsequent requests that need authorization. Using this token and assuming it's in one-to-one relationship with user you can easily identify the user.
I'm currently tyring to build an API driven symfony2 web applicaiton.Just a basic application to learn symfony2 and REST.
It would be based on a RESTful api. Calls to the API will be authenticated using OAuth.
For e.g.:
if a client application wants to get data (information about all the fruits) through API it will need to make a GET request to the url and pass the access token as a parameter.So the url will look something like this.
http://www.mysite.com/api/fruits.json?=<access token>
Now the problem is that i would be needing the same data in one of my actions as well.
I need some help here.In order to get get data from above url in one of my actions i will also need to send an access token in the url.
How do i get this access token??
Should there be a fixed token which will be used for all such calls within my application??
You basic application project will grow manifold if you try to do what you want here.
Basically, you need to implement an Authentication Server for this.
i) First, the app should be registered for a scope;
ii) Using the app the user logs in to the authentication/authorization server.
iii) The server verifies if the app has access to the scope and if the user is registered in your system.
iv) Server creates an access token (which is a HMAC signed string) and returns to your app.
v) The app then hits the endpoint (restful API) with the token.
vi) The RESTful service then internally sends the token to the server and fetches the customerID for which the call is made and performs the actions that it's supposed to.
I wrote an answer once on how to create a OAuth Service/Provider - How would an efficient OAuth2.0 server / provider work?
Also, OAuth was designed such that client apps/3rd party software can access a user's resources on his behalf. A very simple example is = An app posting something on your facebook wall on your behalf. It is actually accessing a resource that you own (the wall) and posting to it. You do not need OAuth just to get some data - there are other ways to secure the API.