How to issue httpOnly cookie using google auth - node.js

I have an API on api.domain.com which using local authentication issues a cookie if user authentication is a success.
The code to demonstrate the logic is right below.
ctx.cookies.set("token", token, {
httpOnly: true,
secure: true,
maxAge: 1000 * 60 * 60 * 24 * 14, // 14 Day Age
domain:"domain.com",
});
After that, the frontend which is hosted at client.domain.com can access that token such that it can be passed as an authorization bearer token, for that reason we all know, but I won't explain.
Everything was working fine until I decided that I wanted to use external providers for authentication.
I managed to integrate Github, and Google OAuth successfully and I can confirm that the authentication flow is flawless except that the httpOnly cookie isn't being issued therefore making it difficult to make requests to those authorized endpoints that require an authorization bearer token.
What I have tried
As above, with the domain option set to domain.com at first, client.domain.com secondly, accounts.google.com but no success up to now.
My question
How do I authenticate using these external providers such that my API api.domain.com can issue an httpOnly cookie
which can be used for that useful purpose on the frontend on client.domain.com when making requests?
Thanks in advance.

Related

How to refresh token after expiry in django knox authentication?

I am running django application with django knox token authentication. I was able to do login with the package.
But after the token expired, url response are throwing " Invalid Token".
I don't understand how to refresh the token after expiry? whether i need to login again? if it is, the user will get irritated.
How to do it in proper way?
Which is the best token authentication for django rest framework?
What worked for me is:
#setting.py
REST_KNOX = {
'TOKEN_TTL': timedelta(hours=10), #time to live (without refresh)
'TOKEN_LIMIT_PER_USER': None,
'AUTO_REFRESH': True,
'MIN_REFRESH_INTERVAL': 60 #number of seconds
}
You can of course change the settings. If you don't specify the 'MIN_REFRESH_INTERVAL' it doesn't work.
The advantage of knox IMOP is that the token refresh is done automatically, and you don't have to do it yourself (unlike JWT, where you need to specifically ask for a new token with the refresh token).
It's less secure than JWT. But the plus is that you have less work to do on the client side.

Nodejs How to bypass the limitation of redirecting without data regarding external auth method?

I have a NodeJS application where I let my users to login via an external auth like Github and Google.
In the frontend I open for the client a tab in Github for example which prompts him to authorize GitHub against my application. I also do this with a callback url. Github then redirects the user back to the callback url I've configured.
Currently this callback URL is an API in my server.
The next step is to redirect the user back to my home page. However, I need to provide the user with some credentials like JWT token.
But I'm limited to send some data along with redirection action. What should I do?
I provide the following data with Github:
super({
clientID: configService.get('githubOAuthClientId', { infer: true }),
clientSecret: configService.get('githubOAuthClientSecret', { infer: true }),
callbackURL: configService.get('githubOAuthRedirectUri', { infer: true }),
scope: ['user:email'],
});
The githubOAuthRedirectUri variable holds my backend api route. Then I handle the data I receive from GitHub in this route controller. Now I want to redirect the user back to the home page but he also needs the JWT token and some more user specific data.
After receiving data from Github, you could redirect to an intermediate page, sending data in url query for example, and then the front-end app redirect to the home page.
That's my idea
I assume that the OAuth provider (Google or GitHub) will invoke your callback URL with an authorization code in a URL parameter ?code=.... Your server must then exchange this authorization code for an access token by making a token request to the OAuth provider. The response to that token request will then contain the access token, which is
either a JWT with a sub claim containing (most likely) the user's email address, see https://stackoverflow.com/a/72590693/16462950
or an "opaque" token, which your server must use in an Authorization: Bearer header of a UserInfo request.
Only after these steps do you know who the user is. Your server could put the JWT in a session cookie so that it is sent again (and must be validated again) in all subsequent requests.
If your server receives an opaque token instead of a JWT, this may be only short-lived and hence cannot be used in a session cookie. In this case, your server could construct its own JWT containing the user info.

Cookie for a refresh-token is not stored

I'm currently struggling with JWT and refresh tokens. I implemented the following flow from the OAuth 2 spec.
The user gets a JWT token which is used for requests and before it expires with the refresh token a new JWT is retrieved.
It works fine, the refresh token is properly returned by the API, but not stored in the cookies storage of the browser. The request for obtaining the token are using { withCredentials: true }
The way how the user gets the refresh token looks like the following. The web app runs on example1.com and the API server on example2.com, both run with https. Is there a error in my cookie configuration or some other mistake in my code?
const cookieOptions = {
httpOnly: true,
expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
secure: true,
sameSite: 'none',
};
res.cookie('refresh_token', token, cookieOptions);
Thanks in advance!
The cookie will be considered third party and browsers drop these aggressively. Aim to convert this to a first party cookie instead, via these steps:
Web app origin is https://www.example.com
API runs at https://api.example.com - a sibling domain
Cookie domain is .example.com
This kind of domain relationship is a prerequisite to using secure cookies these days, due to recent browser restrictions to prevent tracking. I expect your code will work fine once the domain setup is correct.
For further info see this Curity Code Example and the use of a hosts file to test the domain setup. This example also encrypts the cookie using AES256 and uses the cookie setting SameSite=strict.

Session Management problem with http-only cookies Node.js,React

I just confused about session management. For session management , currently im using http-only cookies to store my JWT but these cookies cannot be reached by everyone because of browser's cookie settings which I think is bad for the user experience. So when i search about alternative ways like localstorage. I learned that you are not secure enough in these ways. What would you suggest me to do with the issue I mentioned above? Should i change entire auth system to server-side or any ideas ?
//AUTHENTICATE
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'None',
maxAge: 7 * 24 * 6 * 604800,
});
//LOGOUT
res.cookie('token', '', {
httpOnly: true,
secure: true,
sameSite: 'None',
maxAge: 1,
});
res.clearCookie('token');
You should use httpOnly cookie to prevent access from JS, (with xss attach you can execute JS on other users session).
My suggestion (which us base on The Ultimate Guide to handling JWTs on frontend clients) is to use 2 kind of tokens:
Refresh Token - stored on httpOnly cookie, is used to update the accessToken only, it is valid for long period (no recommended longer than 1 day)
Access Token - stored in memory, attached to each request that needs auth. valid for short period of time (10 mins).
The idea works like this:
User logins, your server validates the credentials and generate an httpOnly cookie with the refreshToken and returns as a response the accessToken.
Your client app sores the accessToken on some class instance (when used with Axios you can attach it as base Authorization header to all requests).
When your app makes a request, it adds the AccessToken as the Authorization header, if the AccessToken expires your api will return 403 UnAuthorized, your client app makes a request to special end point /auth/token with the httpOnly cookie which holds refreshToken, this end point validates the refreshToken, and returns a new accessToken with expiration time of 10mins (which your client app updates the base Auth header with), then your app can retry the previous failed request with the new accessToken.
With this method, there is no access to any kind of tokens from outside of your app.
The refreshToken is not accessible at all to your js and the accessToken is held in memory, only if your app has some flaw it will be exposed, and even if the attacker stole it, it is valid only for 10 mins (without the ability to get a new one because it doesn't have the refreshToken)
For more details read the article I've added.

How can i persist users on my web application with my Node/Express and Firebase backend

Im currently creating a web application using the react/node/express on top of firebase.
Im confused as to how I should persist my user on the client side.
Currently I have sign up and login routes on my Node/Express server that are working and they each return a JWT which I then save to local storage and then add to each request header as a Bearer token.
The problem is that the JWT token expires after 1 hour and the user has to sign in again.
How can I fix this and persist the user forever(if they choose) along with avoiding saving the JWT in local storage. I was looking over the docs and found this https://firebase.google.com/docs/auth/web/auth-state-persistence but im not sure how i would use that with my node/express server.
Firebase accepts session cookies so you can simply create a cookie or a header on the /login endpoint of the backend and return the user as a response if you don't want a solution which includes local storage:
resp.cookie('Authorization', 'Bearer ' + token, {httpOnly: true, secure: false});
return resp.status(200).send({user, events});

Resources