Tokens too big (slow network clients) - how to do lots of roles / claims? - thinktecture-ident-server

The internet connection my clients use is extremely slow... smaller than dial up speed sometimes. Thus, if in my application I need a very large number of roles / claims, the cookie must be transmitted every time - and this would take longer than the actual web page to transfer to the server before the request can be processed (the client upload speed is 1/10th the speed of the download!!!). Is there a way to have the claims exist on the server, or rather, to have the IdentityServer client (the web application on the server) check IdentityServer for claims instead of having to send them all via a token?

Related

What are the benefits of implementing OAuth (JWT access tokens with refresh tokens)

Current Setup
I'm currently building an application, and have just finished implementing an OAuth authentication server. This is my first "real" attempt at a project that has a legitimate user authentication and management component, so much of this is new to me.
I've implemented the OAuth specification. This means the following:
The authentication is deployed on a separate webserver with a separate DB than the application server.
The auth server logs in a user, and issues them two tokens. One is a JWT access token that contains information about their user identity. This has a short-lived 15 minutes expiry. The second token is a refresh-token. This is a single-use token with a 7 day expiry. It is used to fetch another access token with the application server returns a 401 (the access token has expired).
The application server shares a secret key with the auth server, and has middleware that verifies the JWT access token.
Concerns
My concern is that I've over-engineered a project that didn't need this much complexity. Since the auth/app are distinct, this means that my client code needs to be aware of, and handle refresh token rotation. It needs to interpret 401s, and fetch another access token.
As far as I can tell from my reading, this wouldn't be necessary with simple session cookies that persist. The cookie is just included in requests to my domain. If I killed this approach, and just had my server do a DB lookup on a signed session cookie - I would avoid a lot of this client complexity.
One consideration is that I’m using a React SPA frontend client. This is also new territory for me, so I’m not sure whether or not this changes the situation.
As I said above, I'm new to a lot of this so could use some advice from people who have worked in this space for longer and have the experience. Is OAuth worth the hassle?
Options
OAuth with access tokens (JWTs) and refresh tokens:
Pros: Provides a secure and scalable way to handle user sessions.
Cons: Client needs to be aware of refresh token rotation procedure and handle 401 responses by using the refresh token to request a new access token, which can add complexity to the client-side code. Also adds complexity (and cost) to the AWS infra stuff. I need to know how to get the auth server and app server on the same base URI. Also makes my local dev environment a little more involved.
Server-side sessions using signed cookies:
Pros: Simpler for the client, as it does not need to handle refresh tokens or 401 responses.
Cons: Server needs to manage session state, which can be more resource-intensive. This means a DB call on every request.

How to use Google APIs without continuously explicit user consent from a progressive web application?

I have a progressive web application that needs write-access to the Google Drive API for uploading data (media files) the user is creating (either online or offline) in the background while online. It does not really need a server (except for serving the required files, so a static server is sufficient), all of the work could be done on the web application client side.
Since uploading needs to happen on the background, whenever the user is online again (using a service worker and the background sync one-shot API), an access token is not enough for my need (the user can be offline/not use the web application for days) and a refresh token is not supposed to be stored on the web application client side, as far as I understand. Even if it were, I would still need the client secret, which means I have to use a server (or keep the secret within the web application client side, which is a no-no) in order to refresh the token.
It seems like the current ways of using the OAuth2 scheme are at odds with server-less progressive web applications, or I might be missing something. Progressive web applications are more like Chrome applications in this regard, I guess, but I have to supply a Chrome application ID in the Google API console for my application, which I do not (and do not intend to) have and Chrome applications use the Chrome identity API for getting the tokens, which I do not intend to use (and cannot).
I am currently using an actual Node.js server which takes care of the authorization step, keeps the access token and refresh token in a database and returns the existing or new access token to the client, whenever asked. The server is redundant here (and requires a privacy policy for this data which I really do not need to store), I want to do everything using client code, without continuously asking for authorization whenever I upload in the background.
Keeping the refresh token on the web application client side and just reaching out to the server for actually refreshing the access token (nothing must be stored in the server side except the client secret, which is fine), but like I mentioned, I understand the refresh token is not supposed to be kept on the web application side.
Is there a safe and secure way to implement this without a server (or with a server that only gets the refresh token and returns it to the client and refreshes the access token by getting the refresh token from the client)?
It's actually fairly simple, depending on the fine details of your use case.
An important factoid is that once a user has granted permission to your app, he will not have to re-grant it. So you don't need to "continuously asking for authorization whenever I upload in the background". However, the only constraint is that the user must be logged in to Google in order to obtain an Access Token. Normally this isn't an issue, but your app needs to deal with the scenario that a user has logged off from Google, and prompt for login.
All the details are here https://developers.google.com/identity/protocols/OAuth2UserAgent
I suggest avoid the Google JS library because (a) it has its own opinions about the UX, (b) wasn't written with PWAs in mind, (c) has issues on mobile, and (d) is closed source so when it breaks (as it does occasionally), your users are dead in the water until Google fixes it. The page above details the OAuth endpoints so you can easily use them directly. This has the side benefit that adding other cloud storage accounts (AWS, Azure, Drop, etc) is just a case of changing the endpoint URL.
The architecture I use in my PWA is to have my PWA prompt once (and once only) for authorization and then store the user's Gmail address in localStorage. I then have a
hidden iframe which polls once per hour for an Access Token, using the gmail address in a login_hint. This means the iframe is never required to present any UX. The only time UX is required is for the initial auth, which is of course unavoidable, and once per session if the user has logged out of Google.
The only other edge-case you might want to deal with is allowing the user to select between multiple Google accounts, say a personal account and a work domain account.
On a broader point, remember that Google didn't create the OAuth spec so there is little they can do to provide an alternative solution. At an abstract level, auth requires one of the user being present, or secure storage for a permanent token (eg on a server or within a secure store such as Android). Even if we invent OAuth 3, that will still be the case.

Separate authentication server for users and APIs

I'm working on a cloud service authentication system and I'm not entirely sure what the optimal way to handle authenticating requests is. We're planning to run our image server as a separate process from our API server so that we can scale them independently of each other. Handling request authentication with API keys is fairly simple, because we can just have the image server store its own API key and check that requests provide it in a header (over HTTPS obviously), same with the API server. For users though it gets more complex.
Right now we have it setup so that the API server will handle generating a session token and storing users in its database, however what we'd like to do is use 3 servers:
authentication server
API server
image server
and have the image and API servers authenticate requests against the authentication server. How exactly should this be done though? It seems like a bad idea performance-wise to hit the authentication server for every request that the API and image servers make. Can/should a token be verified from a different server than it was created on?
So for example: can/should I pass the token received from the authentication server to the image server, verify that the token came from "my.auth.server" and check that the user ID is the right one? Would JWTs be a good type of token for this?
Here's an alternative approach.
Your authentication issues a JWT token that is signed using a secret that is also available in your API and server images. The reason they need to be there too is that you will need to verify the tokens received to make sure you created them. The nice thing about JWTs is that their payload can hold claims as to what the user is authorised to access should different users have different access control levels.
That architecture renders authentication stateless: No need to store any tokens in a database unless you would like to handle token blacklisting (think banning users). Being stateless is crucial if you ever need to scale. That also frees up your API and image servers from having to call the authentication server at all as all the information they need for both authentication and authorisation are in the issued token.
Flow (no refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server.
User uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
There are a couple of issues here. Namely, that auth token in the wrong hands provides unlimited access to a malicious user to pretend they are the affected user and call your APIs indefinitely. To handle that, tokens have an expiry date and clients are forced to request new tokens whenever expiry happens. That expiry is part of the token's payload. But if tokens are short-lived, do we require users to authenticate with their usernames and password every time? No. We do not want to ask a user for their password every 30min to an hour, and we do not want to persist that password anywhere in the client. To get around that issue, we introduce the concept of refresh tokens. They are longer lived tokens that serve one purpose: act as a user's password, authenticate them to get a new token. Downside is that with this architecture your authentication server needs to persist these refresh token in a database to make them revokable before they expire (think "revoked" column in tokens table).
New flow (with refresh tokens):
User authenticates with the authentication server (eg: POST /auth/login) and receives a JWT token generated and signed by the auth server, alongside a long lived (eg: 6 months) refresh token that they store securely
Whenever the user needs to make an API request, the token's expiry is checked. Assuming it has not yet expired, user uses that token to talk to your API and image servers and assuming user is authorised), gets and posts the necessary resources.
If the token has indeed expired, there is a need to refresh your token, user calls authentication server (EG: POST / auth/token) and passes the securely stored refresh token. Response is a new access token issued.
Use that new token to talk to your API image servers.
OPTIONAL (banning users)
How do we ban users? Using that model there is no easy way to do so. Enhancement: Every persisted refresh token includes a blacklisted field and only issue new tokens if the refresh token isn't black listed.
Things to consider:
You may want to rotate refresh token. To do so, blacklist the refresh token each time your user needs a new access token. That way refresh tokens can only be used once. Downside you will end up with a lot more refresh tokens but that can easily be solved with a job that clears blacklisted refresh tokens (eg: once a day)
You may want to consider setting a maximum number of allowed refresh tokens issued per user (say 10 or 20) as you issue a new one every time they login (with username and password). This number depends on your flow, how many clients a user may use (web, mobile, etc) and other factors.
You can store some additional metadata (ip, geolocation, device, browser cookie, etc.) alongside refresh tokens. That way, you can be smart about when to reject malicious usages of refresh tokens in case it's compromised.
Common Q: Why store all refresh tokens, and not just revoked ones? You could do that. Ask yourself the following: Will I, at any point, need to have a functionality where I can dynamically revoke valid refresh tokens, based on some arbitrary, regulatory, legal, integrity, security etc. criteria? If so, the least you will need is a list of all issued tokens, plus any data required to implement the criterion logic. Example: Due to regulation, I need to ban all EU users equates to a delete from refresh_tokens were user_ip in <... eu logic ...>
one of the best ways to use is a JWT Token , you can generate and share it between all your servers and validate it on the server side .
https://jwt.io
also I think the best architecture to use in this case is the micro service architecture

1hr time limit on tokens used for server-server authentication

Tokens obtained via OAuth 2.0 for service accounts expire after 1 hour.
If an HTTP session is still open while the 1 hour limit is reached (presumably due to many upload/download actions), will the connection stay alive until the session is closed?
Thanks.
--Lee
If you are using OAuth to authenticate users in your website, you probably are not even using the token after the initial exchange with the OAuth provider. Most frameworks will create a cookie based session, for how long this session is valid is up to your setup. Usually the default is to keep the session while the browser is open, but it is really under your control.
On the other side, if you are using OAuth to access some API (for example, if you are using the GMail API to check or send email from inside your web application), then yes, you will not be able to access the API after the token is expired, no matter how much activity was seen while the token was fresh. If you want to keep authorized you need something like a background process to keep renewing the tokens before they expire.

Authentication, Authorization and Session Management in Traditional Web Apps and APIs

Correct me if I am wrong: In a traditional web application, the browser automatically appends session information into a request to the server, so the server can know who the request comes from. What exactly is appended actually?
However, in a API based app, this information is not sent automatically, so when developing an API, I must check myself if the request comes from an authenticated user for example? How is this normally done?
HTTP Protocol is stateless by design, each request is done separately and is executed in a separate context.
The idea behind session management is to put requests from the same client in the same context. This is done by issuing an identifier by the server and sending it to the client, then the client would save this identifier and resend it in subsequent requests so the server can identify it.
Cookies
In a typical browser-server case; the browser manages a list of key/value pairs, known as cookies, for each domain:
Cookies can be managed by the server (created/modified/deleted) using the Set-Cookie HTTP response header.
Cookies can be accessed by the server (read) by parsing the Cookie HTTP request header.
Web-targeted programming languages/frameworks provide functions to deal with cookies on a higher level, for example, PHP provides setcookie/$_COOKIE to write/read cookies.
Sessions
Back to sessions, In a typical browser-server case (again), server-side session management takes advantage of client-side cookie management. PHP's session management sets a session id cookie and use it to identify subsequent requests.
Web applications API?
Now back to your question; since you'd be the one responsible for designing the API and documenting it, the implementation would be your decision. You basically have to
give the client an identifier, be it via a Set-Cookie HTTP response header, inside the response body (XML/JSON auth response).
have a mechanism to maintain identifier/client association. for example a database table that associates identifier 00112233445566778899aabbccddeeff with client/user #1337.
have the client resend the identifier sent to it at (1.) in all subsequent requests, be it in an HTTP Cookie request header, a ?sid=00112233445566778899aabbccddeeff param(*).
lookup the received identifier, using the mechanism at (2.), check if a valid authentication, and is authorized to do requested operation, and then proceed with the operation on behalf on the auth'd user.
Of course you can build upon existing infrastructure, you can use PHP's session management (that would take care of 1./2. and the authentication part of 4.) in your app, and require that client-side implementation do cookie management(that would take care of 3.), and then you do the rest of your app logic upon that.
(*) Each approach has cons and pros, for example, using a GET request param is easier to implement, but may have security implications, since GET requests are logged. You should use https for critical (all?) applications.
The session management is server responsibility. When session is created, a session token is generated and sent to the client (and stored in a cookie). After that, in the next requests between client and server, the client sends the token (usually) as an HTTP cookie. All session data is stored on the server, the client only stores the token. For example, to start a session in PHP you just need to:
session_start(); // Will create a cookie named PHPSESSID with the session token
After the session is created you can save data on it. For example, if you want to keep a user logged:
// If username and password match, you can just save the user id on the session
$_SESSION['userID'] = 123;
Now you are able to check whether a user is authenticated or not:
if ($_SESSION['userID'])
echo 'user is authenticated';
else
echo 'user isn't authenticated';
If you want, you can create a session only for an authenticated user:
if (verifyAccountInformation($user,$pass)){ // Check user credentials
// Will create a cookie named PHPSESSID with the session token
session_start();
$_SESSION['userID'] = 123;
}
There are numerous way for authentic users, both for Web applications and APIs. There are couple of standards, or you can write your own custom authorization / and or authentication. I would like to point out difference between authorization and authentication. First, application needs to authenticate user(or api client) that request is coming from. Once user has been authenticated, based on user's identity application needs to determine whatever authenticated user has permission to perform certain application (authorization). For the most of traditional web applications, there is no fine granularity in security model, so once the user is authenticated, it's in most cases also and authorized to perform certain action. However, this two concepts (authentication and authorization) should be as two different logical operations.
Further more, in classical web applications, after user has been authenticated and authorized
(mostly by looking up username/password pair in database), authorization and identity info is written in session storage. Session storage does not have to be server side, as most of the answers above suggest, it could also be stored in cookie on client side, encrypted in most cases. For an example, PHP CodeIgniter framework does this by default. There is number of mechanism for protecting session on client side, and I don't see this way of storing session data any less secure than storing sessionId, which is then looked up in session storage on server-side. Also, storing session client-side is quite convenient in distributed environment, because it eliminates need for designing solution (or using already existing one) for central session management on server side.
Further more, authenticating with simple user-password pair does not have to be in all case done trough custom code which looks up matching user-record in database. There is, for example basic authentication protocol , or digest authentication. On proprietary software like Windows platform, there are also ways of authenticating user trough, for an example,ActiveDirectory
Providing username/password pair is not only way to authenticate, if using HTTPS protocol, you can also consider authentication using digital certificates.
In specific use case, if designing web service, which uses SOAP as protocol, there is also WS-Security extension for SOAP protocol.
With all these said, I would say that answers to following question enter decision procedure for choice of authorization/authentication mechanism for WebApi:
1) What's the targeted audience, is it publicly available, or for registered(paying) members only?
2) Is it run or *NIX, or MS platform
3) What number of users is expected
4) How much sensitive data API deals with (stronger vs weaker authentication mechanisms)
5) Is there any SSO service that you could use
.. and many more.
Hope that this clears things bit, as there are many variables in equation.
If the API based APP is a Client, then the API must have option to retrieve/read the cookies from server response stream and store it. For automatic appending of cookies while preparing request object for same server/url. If it is not available, session id cannot be retrieved.
You are right, well the reason things are 'automatic' in a standard environment is because cookies are preferred over URL propagation to keep things pretty for the users. That said, the browser (client software) manages storing and sending the session cookie along with every request.
In the API world, simple systems often just have authentication credentials passed along with every request (at least in my line of work). Client authors are typically (again in my experience) reluctant to implement cookie storage, and transmission with every request and generally anything more than the bare minimum...
There are plenty of other authentication mechanisms out there for HTTP-based APIs, HTTP basic / digest to name a couple, and of course the ubiquitous o-auth which is designed specifically for these things if I'm not mistaken. No cookies are maintained, credentials are part of every exchange (fairly sure on that).
The other thing to consider is what you're going to do w/ the session on the server in an API. The session on a website provides storage for the current user, and typically stores small amounts of data to take load off the db from page to page. In an API context this is less of a need as things are more-or-less stateless, speaking generally of course; it really depends what the service is doing.
I would suggest you send some kind of token with each request.
Dependent on the server and service those can be a JSESSIONID parameter in your GET/POST request or something mature like SAML in SOAP over HTTP in your Web Service request.