feat: Remove deprecation DEPPS3: Config option enforcePrivateUsers defaults to true (#8283)
BREAKING CHANGE: The Parse Server option `enforcePrivateUsers` is set to `true` by default; in previous releases this option defaults to `false`; this change improves the default security configuration of Parse Server (#8283)
This commit is contained in:
@@ -6,7 +6,7 @@ The following is a list of deprecations, according to the [Deprecation Policy](h
|
|||||||
|--------|-------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
|
|--------|-------------------------------------------------|----------------------------------------------------------------------|---------------------------------|---------------------------------|-----------------------|-------|
|
||||||
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
|
| DEPPS1 | Native MongoDB syntax in aggregation pipeline | [#7338](https://github.com/parse-community/parse-server/issues/7338) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
|
||||||
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
|
| DEPPS2 | Config option `directAccess` defaults to `true` | [#6636](https://github.com/parse-community/parse-server/pull/6636) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
|
||||||
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | deprecated | - |
|
| DEPPS3 | Config option `enforcePrivateUsers` defaults to `true` | [#7319](https://github.com/parse-community/parse-server/pull/7319) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
|
||||||
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
|
| DEPPS4 | Remove convenience method for http request `Parse.Cloud.httpRequest` | [#7589](https://github.com/parse-community/parse-server/pull/7589) | 5.0.0 (2022) | 6.0.0 (2023) | removed | - |
|
||||||
| DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
|
| DEPPS5 | Config option `allowClientClassCreation` defaults to `false` | [#7925](https://github.com/parse-community/parse-server/pull/7925) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
|
||||||
| DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
|
| DEPPS6 | Auth providers disabled by default | [#7953](https://github.com/parse-community/parse-server/pull/7953) | 5.3.0 (2022) | 7.0.0 (2024) | deprecated | - |
|
||||||
|
|||||||
@@ -292,30 +292,37 @@ describe('ParseGraphQLServer', () => {
|
|||||||
let objects = [];
|
let objects = [];
|
||||||
|
|
||||||
async function prepareData() {
|
async function prepareData() {
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
user1 = new Parse.User();
|
user1 = new Parse.User();
|
||||||
user1.setUsername('user1');
|
user1.setUsername('user1');
|
||||||
user1.setPassword('user1');
|
user1.setPassword('user1');
|
||||||
user1.setEmail('user1@user1.user1');
|
user1.setEmail('user1@user1.user1');
|
||||||
|
user1.setACL(acl);
|
||||||
await user1.signUp();
|
await user1.signUp();
|
||||||
|
|
||||||
user2 = new Parse.User();
|
user2 = new Parse.User();
|
||||||
user2.setUsername('user2');
|
user2.setUsername('user2');
|
||||||
user2.setPassword('user2');
|
user2.setPassword('user2');
|
||||||
|
user2.setACL(acl);
|
||||||
await user2.signUp();
|
await user2.signUp();
|
||||||
|
|
||||||
user3 = new Parse.User();
|
user3 = new Parse.User();
|
||||||
user3.setUsername('user3');
|
user3.setUsername('user3');
|
||||||
user3.setPassword('user3');
|
user3.setPassword('user3');
|
||||||
|
user3.setACL(acl);
|
||||||
await user3.signUp();
|
await user3.signUp();
|
||||||
|
|
||||||
user4 = new Parse.User();
|
user4 = new Parse.User();
|
||||||
user4.setUsername('user4');
|
user4.setUsername('user4');
|
||||||
user4.setPassword('user4');
|
user4.setPassword('user4');
|
||||||
|
user4.setACL(acl);
|
||||||
await user4.signUp();
|
await user4.signUp();
|
||||||
|
|
||||||
user5 = new Parse.User();
|
user5 = new Parse.User();
|
||||||
user5.setUsername('user5');
|
user5.setUsername('user5');
|
||||||
user5.setPassword('user5');
|
user5.setPassword('user5');
|
||||||
|
user5.setACL(acl);
|
||||||
await user5.signUp();
|
await user5.signUp();
|
||||||
|
|
||||||
const roleACL = new Parse.ACL();
|
const roleACL = new Parse.ACL();
|
||||||
@@ -7066,6 +7073,11 @@ describe('ParseGraphQLServer', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
context: {
|
||||||
|
headers: {
|
||||||
|
'X-Parse-Master-Key': 'test',
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.data.createUser.clientMutationId).toEqual(clientMutationId);
|
expect(result.data.createUser.clientMutationId).toEqual(clientMutationId);
|
||||||
@@ -7123,6 +7135,7 @@ describe('ParseGraphQLServer', () => {
|
|||||||
username: 'user2',
|
username: 'user2',
|
||||||
password: 'user2',
|
password: 'user2',
|
||||||
someField: 'someValue2',
|
someField: 'someValue2',
|
||||||
|
ACL: { public: { read: true, write: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
someField: 'someValue',
|
someField: 'someValue',
|
||||||
@@ -7195,6 +7208,7 @@ describe('ParseGraphQLServer', () => {
|
|||||||
username: 'user2',
|
username: 'user2',
|
||||||
password: 'user2',
|
password: 'user2',
|
||||||
someField: 'someValue2',
|
someField: 'someValue2',
|
||||||
|
ACL: { public: { read: true, write: true } },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -8308,19 +8322,21 @@ describe('ParseGraphQLServer', () => {
|
|||||||
const someClass = new Parse.Object('SomeClass');
|
const someClass = new Parse.Object('SomeClass');
|
||||||
await someClass.save();
|
await someClass.save();
|
||||||
|
|
||||||
|
const roleACL = new Parse.ACL();
|
||||||
|
roleACL.setPublicReadAccess(true);
|
||||||
|
|
||||||
const user = new Parse.User();
|
const user = new Parse.User();
|
||||||
user.set('username', 'username');
|
user.set('username', 'username');
|
||||||
user.set('password', 'password');
|
user.set('password', 'password');
|
||||||
|
user.setACL(roleACL);
|
||||||
await user.signUp();
|
await user.signUp();
|
||||||
|
|
||||||
const user2 = new Parse.User();
|
const user2 = new Parse.User();
|
||||||
user2.set('username', 'username2');
|
user2.set('username', 'username2');
|
||||||
user2.set('password', 'password2');
|
user2.set('password', 'password2');
|
||||||
|
user2.setACL(roleACL);
|
||||||
await user2.signUp();
|
await user2.signUp();
|
||||||
|
|
||||||
const roleACL = new Parse.ACL();
|
|
||||||
roleACL.setPublicReadAccess(true);
|
|
||||||
|
|
||||||
const role = new Parse.Role('aRole', roleACL);
|
const role = new Parse.Role('aRole', roleACL);
|
||||||
await role.save();
|
await role.save();
|
||||||
|
|
||||||
@@ -10597,6 +10613,9 @@ describe('ParseGraphQLServer', () => {
|
|||||||
const user = new Parse.User();
|
const user = new Parse.User();
|
||||||
user.setUsername('user1');
|
user.setUsername('user1');
|
||||||
user.setPassword('user1');
|
user.setPassword('user1');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
await user.signUp();
|
await user.signUp();
|
||||||
|
|
||||||
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
|
await parseGraphQLServer.parseGraphQLSchema.schemaCache.clear();
|
||||||
|
|||||||
@@ -1076,6 +1076,9 @@ describe('ParseLiveQuery', function () {
|
|||||||
user.setUsername('username');
|
user.setUsername('username');
|
||||||
user.setPassword('password');
|
user.setPassword('password');
|
||||||
user.set('foo', 'bar');
|
user.set('foo', 'bar');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
|
|
||||||
const query = new Parse.Query(Parse.User);
|
const query = new Parse.Query(Parse.User);
|
||||||
query.equalTo('foo', 'bar');
|
query.equalTo('foo', 'bar');
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
const request = require('../lib/request');
|
const request = require('../lib/request');
|
||||||
|
|
||||||
function setupTestUsers() {
|
function setupTestUsers() {
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
const user1 = new Parse.User();
|
const user1 = new Parse.User();
|
||||||
const user2 = new Parse.User();
|
const user2 = new Parse.User();
|
||||||
const user3 = new Parse.User();
|
const user3 = new Parse.User();
|
||||||
@@ -18,6 +20,10 @@ function setupTestUsers() {
|
|||||||
user2.set('password', 'password');
|
user2.set('password', 'password');
|
||||||
user3.set('password', 'password');
|
user3.set('password', 'password');
|
||||||
|
|
||||||
|
user1.setACL(acl);
|
||||||
|
user2.setACL(acl);
|
||||||
|
user3.setACL(acl);
|
||||||
|
|
||||||
return user1
|
return user1
|
||||||
.signUp()
|
.signUp()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -196,14 +196,13 @@ describe('Parse.User testing', () => {
|
|||||||
const ACL = user.getACL();
|
const ACL = user.getACL();
|
||||||
expect(ACL.getReadAccess(user)).toBe(true);
|
expect(ACL.getReadAccess(user)).toBe(true);
|
||||||
expect(ACL.getWriteAccess(user)).toBe(true);
|
expect(ACL.getWriteAccess(user)).toBe(true);
|
||||||
expect(ACL.getPublicReadAccess()).toBe(true);
|
expect(ACL.getPublicReadAccess()).toBe(false);
|
||||||
expect(ACL.getPublicWriteAccess()).toBe(false);
|
expect(ACL.getPublicWriteAccess()).toBe(false);
|
||||||
const perms = ACL.permissionsById;
|
const perms = ACL.permissionsById;
|
||||||
expect(Object.keys(perms).length).toBe(2);
|
expect(Object.keys(perms).length).toBe(1);
|
||||||
expect(perms[user.id].read).toBe(true);
|
expect(perms[user.id].read).toBe(true);
|
||||||
expect(perms[user.id].write).toBe(true);
|
expect(perms[user.id].write).toBe(true);
|
||||||
expect(perms['*'].read).toBe(true);
|
expect(perms['*']).toBeUndefined();
|
||||||
expect(perms['*'].write).not.toBe(true);
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -875,8 +874,8 @@ describe('Parse.User testing', () => {
|
|||||||
kevin.set('password', 'mypass');
|
kevin.set('password', 'mypass');
|
||||||
await kevin.signUp();
|
await kevin.signUp();
|
||||||
const query = new Parse.Query(Parse.User);
|
const query = new Parse.Query(Parse.User);
|
||||||
const count = await query.count();
|
const count = await query.find({ useMasterKey: true });
|
||||||
equal(count, 2);
|
equal(count.length, 2);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2153,7 +2152,15 @@ describe('Parse.User testing', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("querying for users doesn't get session tokens", done => {
|
it("querying for users doesn't get session tokens", done => {
|
||||||
Parse.User.signUp('finn', 'human', { foo: 'bar' })
|
const user = new Parse.User();
|
||||||
|
user.set('username', 'finn');
|
||||||
|
user.set('password', 'human');
|
||||||
|
user.set('foo', 'bar');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
|
user
|
||||||
|
.signUp()
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return Parse.User.logOut();
|
return Parse.User.logOut();
|
||||||
})
|
})
|
||||||
@@ -2162,6 +2169,9 @@ describe('Parse.User testing', () => {
|
|||||||
user.set('username', 'jake');
|
user.set('username', 'jake');
|
||||||
user.set('password', 'dog');
|
user.set('password', 'dog');
|
||||||
user.set('foo', 'baz');
|
user.set('foo', 'baz');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
return user.signUp();
|
return user.signUp();
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
@@ -2188,7 +2198,14 @@ describe('Parse.User testing', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('querying for users only gets the expected fields', done => {
|
it('querying for users only gets the expected fields', done => {
|
||||||
Parse.User.signUp('finn', 'human', { foo: 'bar' }).then(() => {
|
const user = new Parse.User();
|
||||||
|
user.setUsername('finn');
|
||||||
|
user.setPassword('human');
|
||||||
|
user.set('foo', 'bar');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
|
user.signUp().then(() => {
|
||||||
request({
|
request({
|
||||||
headers: {
|
headers: {
|
||||||
'X-Parse-Application-Id': 'test',
|
'X-Parse-Application-Id': 'test',
|
||||||
@@ -3426,6 +3443,9 @@ describe('Parse.User testing', () => {
|
|||||||
password: 'world',
|
password: 'world',
|
||||||
email: 'test@email.com',
|
email: 'test@email.com',
|
||||||
});
|
});
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
|
|
||||||
reconfigureServer({
|
reconfigureServer({
|
||||||
appName: 'unused',
|
appName: 'unused',
|
||||||
@@ -4057,6 +4077,12 @@ describe('Parse.User testing', () => {
|
|||||||
silent: true,
|
silent: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Parse.Cloud.beforeSave(Parse.User, ({ object }) => {
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
object.setACL(acl);
|
||||||
|
});
|
||||||
|
|
||||||
const query = new Parse.Query(Parse.User);
|
const query = new Parse.Query(Parse.User);
|
||||||
query.doesNotExist('foo');
|
query.doesNotExist('foo');
|
||||||
const subscription = await query.subscribe();
|
const subscription = await query.subscribe();
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ describe('ProtectedFields', function () {
|
|||||||
user.setPassword('sekrit');
|
user.setPassword('sekrit');
|
||||||
user.set('email', 'alice@aol.com');
|
user.set('email', 'alice@aol.com');
|
||||||
user.set('favoriteColor', 'yellow');
|
user.set('favoriteColor', 'yellow');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
||||||
@@ -35,6 +38,9 @@ describe('ProtectedFields', function () {
|
|||||||
user.set('timeZone', 'America/Los_Angeles');
|
user.set('timeZone', 'America/Los_Angeles');
|
||||||
user.set('favoriteColor', 'yellow');
|
user.set('favoriteColor', 'yellow');
|
||||||
user.set('favoriteFood', 'pizza');
|
user.set('favoriteFood', 'pizza');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
||||||
@@ -57,6 +63,9 @@ describe('ProtectedFields', function () {
|
|||||||
user.set('timeZone', 'America/Los_Angeles');
|
user.set('timeZone', 'America/Los_Angeles');
|
||||||
user.set('favoriteColor', 'yellow');
|
user.set('favoriteColor', 'yellow');
|
||||||
user.set('favoriteFood', 'pizza');
|
user.set('favoriteFood', 'pizza');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
const fetched = await new Parse.Query(Parse.User).get(user.id);
|
||||||
@@ -108,6 +117,9 @@ describe('ProtectedFields', function () {
|
|||||||
user.set('timeZone', 'America/Los_Angeles');
|
user.set('timeZone', 'America/Los_Angeles');
|
||||||
user.set('favoriteColor', 'yellow');
|
user.set('favoriteColor', 'yellow');
|
||||||
user.set('favoriteFood', 'pizza');
|
user.set('favoriteFood', 'pizza');
|
||||||
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
user.setACL(acl);
|
||||||
await user.save();
|
await user.save();
|
||||||
|
|
||||||
const objA = await new Parse.Object('ClassA').set('foo', 'zzz').set('bar', 'yyy').save();
|
const objA = await new Parse.Object('ClassA').set('foo', 'zzz').set('bar', 'yyy').save();
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ describe('rest query', () => {
|
|||||||
let user = {
|
let user = {
|
||||||
username: 'aUsername',
|
username: 'aUsername',
|
||||||
password: 'aPassword',
|
password: 'aPassword',
|
||||||
|
ACL: { '*': { read: true } },
|
||||||
};
|
};
|
||||||
const activity = {
|
const activity = {
|
||||||
type: 'comment',
|
type: 'comment',
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ describe('Personally Identifiable Information', () => {
|
|||||||
await reconfigureServer();
|
await reconfigureServer();
|
||||||
user = await Parse.User.signUp('tester', 'abc');
|
user = await Parse.User.signUp('tester', 'abc');
|
||||||
user = await Parse.User.logIn(user.get('username'), 'abc');
|
user = await Parse.User.logIn(user.get('username'), 'abc');
|
||||||
await user.set('email', EMAIL).set('zip', ZIP).set('ssn', SSN).save();
|
const acl = new Parse.ACL();
|
||||||
|
acl.setPublicReadAccess(true);
|
||||||
|
await user.set('email', EMAIL).set('zip', ZIP).set('ssn', SSN).setACL(acl).save();
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ describe('Custom Pages, Email Verification, Password Reset', () => {
|
|||||||
'Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user'
|
'Found. Redirecting to http://localhost:8378/1/apps/verify_email_success.html?username=user'
|
||||||
);
|
);
|
||||||
user
|
user
|
||||||
.fetch()
|
.fetch({ useMasterKey: true })
|
||||||
.then(
|
.then(
|
||||||
() => {
|
() => {
|
||||||
expect(user.get('emailVerified')).toEqual(true);
|
expect(user.get('emailVerified')).toEqual(true);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
* If there are no deprecations, this must return an empty array.
|
* If there are no deprecations, this must return an empty array.
|
||||||
*/
|
*/
|
||||||
module.exports = [
|
module.exports = [
|
||||||
{ optionKey: 'enforcePrivateUsers', changeNewDefault: 'true' },
|
|
||||||
{ optionKey: 'allowClientClassCreation', changeNewDefault: 'false' },
|
{ optionKey: 'allowClientClassCreation', changeNewDefault: 'false' },
|
||||||
{ optionKey: 'allowExpiredAuthDataToken', changeNewDefault: 'false' },
|
{ optionKey: 'allowExpiredAuthDataToken', changeNewDefault: 'false' },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ module.exports.ParseServerOptions = {
|
|||||||
env: 'PARSE_SERVER_ENFORCE_PRIVATE_USERS',
|
env: 'PARSE_SERVER_ENFORCE_PRIVATE_USERS',
|
||||||
help: 'Set to true if new users should be created without public read and write access.',
|
help: 'Set to true if new users should be created without public read and write access.',
|
||||||
action: parsers.booleanParser,
|
action: parsers.booleanParser,
|
||||||
default: false,
|
default: true,
|
||||||
},
|
},
|
||||||
expireInactiveSessions: {
|
expireInactiveSessions: {
|
||||||
env: 'PARSE_SERVER_EXPIRE_INACTIVE_SESSIONS',
|
env: 'PARSE_SERVER_EXPIRE_INACTIVE_SESSIONS',
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ export interface ParseServerOptions {
|
|||||||
:DEFAULT: {} */
|
:DEFAULT: {} */
|
||||||
security: ?SecurityOptions;
|
security: ?SecurityOptions;
|
||||||
/* Set to true if new users should be created without public read and write access.
|
/* Set to true if new users should be created without public read and write access.
|
||||||
:DEFAULT: false */
|
:DEFAULT: true */
|
||||||
enforcePrivateUsers: ?boolean;
|
enforcePrivateUsers: ?boolean;
|
||||||
/* Allow a user to log in even if the 3rd party authentication token that was used to sign in to their account has expired. If this is set to `false`, then the token will be validated every time the user signs in to their account. This refers to the token that is stored in the `_User.authData` field. Defaults to `true`.
|
/* Allow a user to log in even if the 3rd party authentication token that was used to sign in to their account has expired. If this is set to `false`, then the token will be validated every time the user signs in to their account. This refers to the token that is stored in the `_User.authData` field. Defaults to `true`.
|
||||||
:DEFAULT: true */
|
:DEFAULT: true */
|
||||||
|
|||||||
Reference in New Issue
Block a user