JwtBearerAuthentication in AspNetCore.Authentication.JwtBearer and refresh token - asp.net-core

I am using aspnetcore in visual studio 2015.
I've implemented JwtBearerAuthentication and I am successfully using token authentication. So users login and get a token.
Now, my tokens have an expiration time span. After they expire, users can no longer be validated. I want to be able to refresh the user's token silently in the client a couple minutes before the expiration. How can I achieve so in this setup? Is it possible with Microsoft.AspNetCore.Authentication.JwtBearer?

Yes it's possible. You can create a refresh-token (for example a random string) and set an expiration time more than your secret token. Send this token to your client, and save it in the client. Whenever the main token expires you can send the refresh token to server and check it,
instead of sending the user to the login page (and creating a new token).
If it has not expires yet, you create a new token and refresh token and set access to user, your header must contain:
This site says...
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJlUzl1NiJ9.eyJ1bmlxdWVfbmFtZ...",
"token_type": "bearer",
"expires_in": 119,
"refresh_token": "9b091854a9d3415c8ae12f07c333e5...",
}

Related

How to handle JWT refreshing on server side (Next.js or any other)

I have two cookies being stored: JWT and refresh token, both are httponly; path=/, so they are send on all requests, including the API (which doesn't use Bearer, but instead reads the JWT directly from the cookies).
The implementation is as usual, the JWT is short lived, and the refresh token is used to get a new one. The refresh token is rotating and after used is invalidated.
On the client, refreshing the token is no issue. When a 401 is returned by the API a call is made to /auth/refresh-token and the request is retried.
On the server however, (e.g. on getServerSideProps) it seems to be quite difficult to refresh the JWT. What I have attempted is to create a custom server and a middleware that checks when a JWT is expired and attempts to refresh it.
I can think of two issues with that, first is that the custom server is called on every resource, that includes all json, js, static files, etc... that Next.js serves. When two requests are made with the same tokens (I can handle this when making API calls, but Next.js also sends requests to the server and I cannot control those):
1. Two requests with expired JWT are sent to the server
2. The back-end receives the requests and on both determines it needs to refresh the token
3. Eventually one of the requests will complete, invalidating the refresh-token
4. The other request now has an invalidated refresh token and cannot get a new JWT
Second issue, what if the user doesn't receive the response, scenario:
1. A request with an expired JWT is sent
2. The back-end refreshes it and sets the new cookies
3. The back-end then has to read lots of data from a database which takes a few seconds
4. User closes the page before receiving the response
5. At this point the user has an invalidated refresh token and an expired JWT because the response with the new cookies was never received
How are these cases usually handled? It seems like it would be a common issue with rotating refresh tokens, but I couldn't find anything useful on this online.
You can follow this practice.
Save refresh token in the http-only cookie
No need to save JWT in the cookie for better security and keep it in the response of refresh token as well as login endpoint.
Save JWT expiry in a normal cookie
Call refresh token endpoint to get new JWT when expiry token is not present or getting 401 error.
In getServerSideProps also you can call the refresh token endpoint always as you don't need to persist JWT anywhere.
You may need to get the cookie from req.headers.cookie and pass it in the header when you are calling the refresh token endpoint from the server.
//inside getServerSideProps
const browserCookie = req.headers.cookie;
const refreshJWTTokenResponse: any = await refreshJWTToken(browserCookie);
//service call
export async function refreshJWTToken(refreshTokenCookie: any): Promise<{}> {
let headers = new Headers();
headers.append("Cookie",`${refreshTokenCookie}`);
const options = {
method: 'POST',
headers: headers,
credentials:'include',
};
...
}

Secure way to store authorization data inside a PWA

I am trying to design a secure API, which then will be used by a PWA on desktop and mobile.
I have the following flow:
A POST request with the user's credentials is issued to endpoint /session at login.
If the the credentials are correct it will set a Secure, HttpOnly cookie which contains a refresh token with Path=/session/renew. This way it's only sent to that endpoint, cannot be accessed from JavaScript, and will only be set on HTTPS.
The response will also contain a JSON object with an access token. This will be used for every other authorized request. It will be passed along in a Authorization: Bearer ${access_token} header. The token's max age is 30 minutes.
Before the access token expires I can call to /session/renew with the cookie set and this will give me new access token and will also set the new refresh token in the cookie with the same properties as above. The old tokens will be revoked on the server.
The access token is stored in a Redux store. Unfortunately, this poses a problem.
Now if open a new tab, I can request a new token on /session/renew, but with this setup I will "stole" the previous tab's ability to request new tokens as those will be revoked by this call and the user will just get logged-out on that tab.
I see a few solutions, but none seems to be secure enough to me:
Don't revoke the old access and renew tokens when /session/renew is called
Store the access token in session or local storage
I did quite some research and still don't see what would be the correct (and not too complicated) solution here.

Proper way to do jwt refresh tokens with express

I'm thinking of a proper pattern for implementing refresh tokens, but on few steps, I have some questions. I am using nextjs with axios on the frontend and express with cookie-session on the backend.
Here are steps I'm thinking of:
Client sends a log-in request. After logging in I put the access token in the session object and the refresh token into res.cookie, both secure and httpOnly.
// for simplicity options are left out
req.session = { accessToken };
res.cookie("refreshToken", refreshToken)
On every request with axios I supply just the access token. Here's where the first question arises. How would I supply only the access token, without sending the refresh token too, if both are httpOnly?
If the access token is valid do whatever is needed. If not, need to get the refresh token and compare it to a stored one, and so on. Here's the second question. While I understand I need to retrieve the refresh token in this step, how would I do it properly?
Any more advice would be great, thanks.
[EDIT] After some thought I realised that making access token not httpOnly would allow me to send just access token, which would solve my problem. But if that is incorrect please let me know.
Here is the standard pattern - as in this code of mine:
Client sends access token (which may be in an HTTP Only cookie)
When it expires they try to refresh the access token by calling a /refresh endpoint
If the refresh succeeds they retry the API request with the new access token
Otherwise the client redirects the user to sign in again
Don't make the access token non HTTP Only, since any malicious code could then grab it from document.cookie.
This also allows you to set a path of /refresh for the RT cookie, so that it is only sent on refresh requests.
Also ensure that cookies containing tokens are strongly encrypted (AES256) using a symmetric key only known server side. This Express library will do the work for you.

django rest framework - token authentication logout

I have implemented the Token Authentication according to the django rest framework Docs.
Form what I read, the Token Authentication of DRF is quite simple - one token per user, the token doesn't expire and is valid for use always (am I right?).
I understand that there are better practices out there, but for now the DRF token authentication is fine for me.
my question is- what is the best practice for logout with the normal DRF token authentication?
I mean, when the user logs out, should I delete the token from the client side? and then on login get the token again? should I delete the token and generate a new one?
Anyone with experience with this?
Here's a simple view that I'm using to log out:
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
class Logout(APIView):
def get(self, request, format=None):
# simply delete the token to force a login
request.user.auth_token.delete()
return Response(status=status.HTTP_200_OK)
Then add it to your urls.py:
urlpatterns = [
...
url(r'^logout/', Logout.as_view()),
]
WHOLE IDEA OF TOKEN AUTHENTICATION:
Normally in authentication services, there is a lifetime associated with a token. After a specific time, the token will get expired. Here, we get an access token which has an expiry time sent along with it by the server. Now the client needs to send this token everytime in the request header so that the server can identify who the user is. Either we can keep track of when it expires or we can just keep using it until we get an INVALID_TOKEN error. In that case we would have to again get the token from the server.
The lifetime of the access_token is independent of the login session of a user who grants access to a client. OAuth2,lets say, has no concept of a user login or logout, or a session. The token is just used to identify the user if he is who he says he is.
The token is unique for a user and client. You may save it to cookies to enable something like remember me but on the server you don't need to delete it. Whenever the token expires, the client need to send a request to the server to obtain the token again.
Token Expiry in DRF Token Authetication:
Currently, DRF Token authentication does not support this functionality. You would have to implement it yourself or use a third party package which provides this functionality. It should check for token expiry and raise an exception if the token has expired.
To implement it yourself, you can subclass from the DRF Token Authentication class and add your logic.
You can even use a third-party package django-rest-framework-expiring-tokens.
Some References:
1. Token Authentication for RESTful API: should the token be periodically changed?
2. How to Logout of an Application Where I Used OAuth2 To Login With Google?
It sounds like SessionAuthentication is what you are really looking. You can start(login) a session via BasicAuthentication or TokenAuthentication. Then use sessionid as your "token" for the rest of api calls. The "token" expires when you logout or exceed certain timing.
If you run into csrftoken issue using session authentication, this could be a very helpful.

Google Drive API accessing both "online" and "offline" at the same time

This is a follow up to my previous question: How do I access Google Drive Application Data from a remote server?
I have an application which needs to access Google Drive AppFolder both client-side (online, JavaScript) and server-side (offline, Python). My application is unique in that the client and the server may not be able to communicate past the original authentication.
Thus, I use the following to obtain an auth token for the server (initiated client-side):
gapi.auth.authorize({
'client_id': CLIENT_ID,
'scope': SCOPES,
'access_type': 'offline',
'response_type': 'code',
'state': 'my_state',
}, null, 2),
'redirect_uri': 'http://server/oauth2callback',
'immediate': false
},
handleOfflineAuthResult);
the server stores the credentials including refresh token.
Then the client (in a subsequent user session) sends requests directly to Google Drive for token:
gapi.auth.authorize({
'client_id': CLIENT_ID,
'scope': SCOPES,
'immediate': true
}, handleAuthResult);
now when the client does that it gets a refresh token but invalidates the refresh_token for the server. Thus my server can no longer refresh its token and gets 'AccessTokenRefreshError: invalid_grant'.
Is there any way to solve this problem assuming the client and the server cannot communicate past the original authentication (i.e. the client can't just ask the server for its auth_token, that's by design) ?
The only "solution" I have thought of is to have the client store its auth_token and refresh_token in the AppFolder and the server continuously pull the AppFolder for new credentials, subsequently replacing its copy with the client one.
You say
when the client does that [calls gapi.auth.authorize] it gets a refresh token but invalidates the
refresh_token for the server
At least the first part is incorrect, and I suspect the second part is too. gapi.auth.authorize returns an access token, not a refresh token (see https://developers.google.com/api-client-library/javascript/reference/referencedocs#OAuth20TokenObject).
I doubt very much that requesting an access token for your client is invalidating a refresh token for your server. If you are 100% sure that it is, you should use a separate client ID for each of your JS and web client apps. Note that a JS client will never use a refresh token, as this would be a major security flaw. JS clients always request access tokens as needed, either from your server or from Google.