When Using the NextJS _middleware.js cookie is fetched by it during development in localhost, but as soon as I deploy onto vercel it stops fetching the cookie.
The Cookie is httpOnly and the cookie is present on the website but is not being fetched by the middleware in production.
Here is my middleware code
import { NextResponse } from "next/server";
export async function middleware(req) {
let token = req.cookies["refreshToken"];
console.log(token);
const { origin } = req.nextUrl
const url = req.url
if (url.includes('/profile') && !token) {
return NextResponse.redirect(`${origin}/`)
}
if (token && url.includes('/profile')) {
return NextResponse.next()
}
}
Any Suggestions? or does it not work cross site ?, but I am able to store the cookie, keep that in mind.
It might be a cross-site request issue. If your backend is hosted on a different domain and you set the cookie with the SameSite attribute set to lax or strict, your frontend code won't have access to it (see MDN).
Related
I have a SSR Nuxt app. There is a middleware in the page code.
I dont know is I can use js-cookies library in that middleware and if it will work as I expected. I need to get and set up the cookie in browser and also get the cookie value on the server. All this steps in the middleware.
I mean
check if cookie is set via Cookies.get(key)
if not then set up the cookie via Cookies.set(key, value)
redirect to the server where I want to get this cookie value
Code should look like
async middleware(context) {
const token = context.route.query.token;
if (!token) {
const cookieToken = Cookies.get('cookieToken');
if( !cookieToken ) {
Cookies.set('cookieTokne', nanoId());
}
const result = await context.$api.campaignNewShare.createNewShare();
context.redirect({'name': 'campaigns-new', 'query': {token: result.data.token}});
}
},
Am I able to get cookie after the set on the server and can I get it in the browser after the redirect? I need to ensure both set and get in this middleware at once.
Use nuxt universal cookies and register on your modules, this way you can access the module everywhere on your nuxt app.
Using your code as example:
async middleware(context) {
const token = context.route.query.token;
if (!token) {
const cookieToken = context.$cookies.get('cookieToken');
if( !cookieToken ) {
context.$cookies.set('cookieToken', nanoId());
}
const result = await context.$api.campaignNewShare.createNewShare();
context.redirect({'name': 'campaigns-new', 'query': {token: result.data.token}});
}
},
I'm using a django backend, and a CRAO frontend. I saved the jwt refresh token as a httponly cookie:
document.cookie = `refresh=${refresh_token}; SameSite=Strict; Path=/api/token/refresh; HttpOnly`;
Then to refresh the access token, I'm sending an axios request:
const response = await axios.post('/api/token/refresh/', { withCredentials: true });
But, in this case, the originally saved cookies don't get sent by axios. However, on removing the httponly attribute, the cookies do get sent, and everything works fine.
You did not set the cookie well in your django app. follow up this way to save it as httponly cookie:
response.set_cookie(
key=settings.SIMPLE_JWT["AUTH_COOKIE_REFRESH"],
value=token["refresh"],
expires=settings.SIMPLE_JWT["ACCESS_TOKEN_LIFETIME"],
secure=settings.SIMPLE_JWT["AUTH_COOKIE_SECURE"],
httponly=settings.SIMPLE_JWT["AUTH_COOKIE_HTTP_ONLY"],
samesite=settings.SIMPLE_JWT["AUTH_COOKIE_SAMESITE"],
)
Like to ask a CORS cookie question again, I have spent quite some time on this but cannot resolve it.
Here is the situation.
I got a Backend api in nodejs(http://localhost:5000), and a React Frontend app(http://localhost:3000).
In Backend side, Cors setting is like this.
private initializeCors(){
this.app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "http://localhost:3000");
res.header("Access-Control-Allow-Headers", "Content-Type, Accept");
res.header("Access-Control-Allow-Credentials", "true");
next();
});
}
I have set { credentials: "include" } in Fetch Api when login with username/password.
Set-Cookie has been set in response and I can see it saved in browser.
Cookie is with the format "Authorize=TOKEN;HttpOnly;Max-Age=3600;"
Cookie in browser
Then when route to another url and it cannot retrieve data from Backend with 401 exception.
Here is the code of the sequence call.
const credentialsInclude : "include" | "omit" | "same-origin" | undefined = "include";
function getAllPayments() {
const requestOptions = {
method: 'GET',
credentials: credentialsInclude
};
return fetch(apiUrls.GET_ALL_PAYMENTS, requestOptions).then(handleResponse);
}
I can see the cookie not added into header.
No cookie in header
I have followed the best answer of here, but cannot get it work.
Any suggestions? Thanks.
I have just figured out. The issue was not caused by the CORS settings. It caused by the Cookie itself.
For my case, I need to add Path=/; into Set-Cookie in response headers. So that the cookie from response could be added to sequenced requests after successful login.
I have an ASP.NET Identity site and a ASP.NET OData site.
Both sites have CORS enabled and both site are using ASP.NET Identity CookieAuthentication.
When I execute both sites locally on my computer using IIS (not express) the AUTH cookie is being passed in the header on each request to the OData site.
But when I deploy the sites to the production IIS server then the header is missing the AUTH cookie when calling the production OData site.
Both production and my local IIS have the same domain name and CORS is setup to allow all.
The WebApiConfig has
cors = new Http.Cors.EnableCorsAttribute("*", "*", "*");
config.Enable(cors);
Before anyone asks, yes the machine key is the same between sites.
UPDATE
This seems to be a CORS issue.
When both sites are on my local machine they use the same host name and domain name but when the site are on the production server they have different host names and the same domain name.
You might need to specify the "Access-Control-Allow-Origin" inside your OAuthAuthorizationServerProvider.
I'm using OWIN but you should be able to do something similarly.
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
try adding the policy in your OWIN startup class as below. Just keep in mind that the Startup class might have some different class files since it's a partial class. Also, check ConfigureAuth method to see if everything is set according to your needs there. For instance, you set the external signin cookie of Identity as copied below in ConfigureAuth method to allow External Signin Cookeies like facebook and google.
public void Configuration(IAppBuilder app)
{
//
app.UseCors(CorsOptions.AllowAll);
ConfigureAuth(app);
}
app.UseExternalSignInCookie(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ExternalCookie);
I finally got this to work.
In the ASP.NET Identity site I have the following:
// configure OAuth for login
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
Provider = new CookieAuthenticationProvider(),
LoginPath = new PathString("/Account/Login.aspx"),
CookieName = ".TESTAUTH",
CookieDomain = ".test.com",
CookieSecure = CookieSecureOption.Always
});
It seems that the important part on the ASP.NET Identity site is that the "CookieName, CookieDomain, and the Machine Key" must match the one on the OData site.
And then on the OData site I have the following:
// configure OAuth for login
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
Provider = new CookieAuthenticationProvider { OnApplyRedirect = ApplyRedirect },
LoginPath = new PathString("/Account/Login.aspx"),
CookieName = ".TESTAUTH",
CookieDomain = ".test.com",
CookieSecure = CookieSecureOption.Always
});
// build the configuration for web api
HttpConfiguration config = new HttpConfiguration();
// Enable CORS (Cross-Origin Resource Sharing) for JavaScript / AJAX calls
// NOTE: USING ALL "*" IS NOT RECOMMENDED
var cors = new Http.Cors.EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
// call the web api startup
WebApiConfig.Register(config);
app.UseWebApi(config);
private void ApplyRedirect(CookieApplyRedirectContext context)
{
Uri absoluteUri = null;
if (Uri.TryCreate(context.RedirectUri, UriKind.Absolute, absoluteUri))
{
var path = PathString.FromUriComponent(absoluteUri);
if (path == context.OwinContext.Request.PathBase + context.Options.LoginPath)
{
QueryString returnURI = new QueryString(context.Options.ReturnUrlParameter, context.Request.Uri.AbsoluteUri);
context.RedirectUri = "https://www.test.com/Account/Login.aspx" + returnURI.ToString;
}
}
context.Response.Redirect(context.RedirectUri);
}
The "LoginPath" is required even though it does not exist on the OData site and you can't use a full url to another site for the login path.
I used "OnApplyRedirect" to redirect to the actual Login page.
I'm not sure what the difference is between "config.EnableCors" and "app.UseCors" but the EnableCors seems to be working for now.
I have just pushed a web app into production and requests to my nodejs no longer contain the user cookie that Django has been setting by default on my localhost (where it was working).
my nodejs looks for the cookie like this
io.configure(function(){
io.set('authorization', function(data, accept){
if (data.headers.cookie) {
data.cookie = cookie_reader.parse(data.headers.cookie);
return accept(null, true);
}
return accept('error',false);
});
io.set('log level',1);
});
and on localhost has been getting this
cookie: 'username="name:1V7yRg:n_Blpzr2HtxmlBOzCipxX9ZlJ9U"; password="root:1V7yRg:Dos81LjpauTABHrN01L1aim-EGA"; csrftoken=UwYBgHUWFIEEKleM8et1GS9FuUPEmgKF; sessionid=6qmyso9qkbxet4isdb6gg9nxmcnw4rp3' },
in the request header.
But in production, the header is the same but except no more cookie. Does Django only set this on localhost? How can I get it working in production?
I've tried setting these in my settings.py
CSRF_COOKIE_DOMAIN = '.example.com'
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = False
But so far no good.
Any insight would be great.
I just figured it out. I was making a request to nodejs on the client like this
Message.socket = io.connect('http://123.456.789.10:5000');
Where I used my respective IP address and port that my nodejs was listening on. This is considered cross domain so browsers won't include cookies in the request. Easy fix by changing it to
Message.socket = io.connect('http://www.mydomain.com:5000');