mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat(core)!: Set the secure
flag on issued cookies (#8812)
This commit is contained in:
parent
2b0e14e936
commit
0818824a72
|
@ -2,6 +2,16 @@
|
||||||
|
|
||||||
This list shows all the versions which include breaking changes and how to upgrade.
|
This list shows all the versions which include breaking changes and how to upgrade.
|
||||||
|
|
||||||
|
## 1.32.0
|
||||||
|
|
||||||
|
### What changed?
|
||||||
|
|
||||||
|
N8n auth cookie has `Secure` flag set by default now.
|
||||||
|
|
||||||
|
### When is action necessary?
|
||||||
|
|
||||||
|
If you are running n8n without HTTP**S** on a domain other than `localhost`, you need to either setup HTTPS, or you can disable the secure flag by setting the env variable `N8N_SECURE_COOKIE` to `false`.
|
||||||
|
|
||||||
## 1.27.0
|
## 1.27.0
|
||||||
|
|
||||||
### What changed?
|
### What changed?
|
||||||
|
|
|
@ -82,6 +82,7 @@ export class AuthService {
|
||||||
maxAge: this.jwtExpiration * Time.seconds.toMilliseconds,
|
maxAge: this.jwtExpiration * Time.seconds.toMilliseconds,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
|
secure: config.getEnv('secure_cookie'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ if (inE2ETests) {
|
||||||
process.env.N8N_LOG_LEVEL = 'silent';
|
process.env.N8N_LOG_LEVEL = 'silent';
|
||||||
process.env.N8N_PUBLIC_API_DISABLED = 'true';
|
process.env.N8N_PUBLIC_API_DISABLED = 'true';
|
||||||
process.env.SKIP_STATISTICS_EVENTS = 'true';
|
process.env.SKIP_STATISTICS_EVENTS = 'true';
|
||||||
|
process.env.N8N_SECURE_COOKIE = 'false';
|
||||||
} else {
|
} else {
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
}
|
}
|
||||||
|
|
|
@ -538,6 +538,12 @@ export const schema = {
|
||||||
env: 'N8N_PROTOCOL',
|
env: 'N8N_PROTOCOL',
|
||||||
doc: 'HTTP Protocol via which n8n can be reached',
|
doc: 'HTTP Protocol via which n8n can be reached',
|
||||||
},
|
},
|
||||||
|
secure_cookie: {
|
||||||
|
doc: 'This sets the `Secure` flag on n8n auth cookie',
|
||||||
|
format: Boolean,
|
||||||
|
default: true,
|
||||||
|
env: 'N8N_SECURE_COOKIE',
|
||||||
|
},
|
||||||
ssl_key: {
|
ssl_key: {
|
||||||
format: String,
|
format: String,
|
||||||
default: '',
|
default: '',
|
||||||
|
|
|
@ -90,6 +90,7 @@ describe('AuthService', () => {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
maxAge: 604800000,
|
maxAge: 604800000,
|
||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
|
secure: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -177,6 +178,7 @@ describe('AuthService', () => {
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
maxAge: 604800000,
|
maxAge: 604800000,
|
||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
|
secure: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { CookieOptions, Response } from 'express';
|
import type { Response } from 'express';
|
||||||
import { Container } from 'typedi';
|
import { Container } from 'typedi';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { mock, anyObject, captor } from 'jest-mock-extended';
|
import { mock, anyObject } from 'jest-mock-extended';
|
||||||
import type { PublicUser } from '@/Interfaces';
|
import type { PublicUser } from '@/Interfaces';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import { MeController } from '@/controllers/me.controller';
|
import { MeController } from '@/controllers/me.controller';
|
||||||
|
@ -11,10 +11,10 @@ import { UserService } from '@/services/user.service';
|
||||||
import { ExternalHooks } from '@/ExternalHooks';
|
import { ExternalHooks } from '@/ExternalHooks';
|
||||||
import { InternalHooks } from '@/InternalHooks';
|
import { InternalHooks } from '@/InternalHooks';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
import { badPasswords } from '../shared/testData';
|
|
||||||
import { mockInstance } from '../../shared/mocking';
|
|
||||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||||
import { UserRepository } from '@/databases/repositories/user.repository';
|
import { UserRepository } from '@/databases/repositories/user.repository';
|
||||||
|
import { badPasswords } from '../shared/testData';
|
||||||
|
import { mockInstance } from '../../shared/mocking';
|
||||||
|
|
||||||
describe('MeController', () => {
|
describe('MeController', () => {
|
||||||
const externalHooks = mockInstance(ExternalHooks);
|
const externalHooks = mockInstance(ExternalHooks);
|
||||||
|
@ -63,10 +63,16 @@ describe('MeController', () => {
|
||||||
|
|
||||||
expect(userService.update).toHaveBeenCalled();
|
expect(userService.update).toHaveBeenCalled();
|
||||||
|
|
||||||
const cookieOptions = captor<CookieOptions>();
|
expect(res.cookie).toHaveBeenCalledWith(
|
||||||
expect(res.cookie).toHaveBeenCalledWith(AUTH_COOKIE_NAME, 'signed-token', cookieOptions);
|
AUTH_COOKIE_NAME,
|
||||||
expect(cookieOptions.value.httpOnly).toBe(true);
|
'signed-token',
|
||||||
expect(cookieOptions.value.sameSite).toBe('lax');
|
expect.objectContaining({
|
||||||
|
maxAge: expect.any(Number),
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: 'lax',
|
||||||
|
secure: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
expect(externalHooks.run).toHaveBeenCalledWith('user.profile.update', [
|
expect(externalHooks.run).toHaveBeenCalledWith('user.profile.update', [
|
||||||
user.email,
|
user.email,
|
||||||
|
@ -175,10 +181,16 @@ describe('MeController', () => {
|
||||||
|
|
||||||
expect(req.user.password).not.toBe(passwordHash);
|
expect(req.user.password).not.toBe(passwordHash);
|
||||||
|
|
||||||
const cookieOptions = captor<CookieOptions>();
|
expect(res.cookie).toHaveBeenCalledWith(
|
||||||
expect(res.cookie).toHaveBeenCalledWith(AUTH_COOKIE_NAME, 'new-signed-token', cookieOptions);
|
AUTH_COOKIE_NAME,
|
||||||
expect(cookieOptions.value.httpOnly).toBe(true);
|
'new-signed-token',
|
||||||
expect(cookieOptions.value.sameSite).toBe('lax');
|
expect.objectContaining({
|
||||||
|
maxAge: expect.any(Number),
|
||||||
|
httpOnly: true,
|
||||||
|
sameSite: 'lax',
|
||||||
|
secure: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
expect(externalHooks.run).toHaveBeenCalledWith('user.password.update', [
|
expect(externalHooks.run).toHaveBeenCalledWith('user.password.update', [
|
||||||
req.user.email,
|
req.user.email,
|
||||||
|
|
Loading…
Reference in a new issue