Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions spec/AuthenticationAdaptersV2.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1702,4 +1702,32 @@ describe('Auth Adapter features', () => {
expect(res.status).toBeLessThan(500);
});
});

it('does not crash fetching a _User with stale authData from a removed built-in provider (#10526)', async () => {
// Configure a built-in code-auth provider, then simulate a _User that still carries
// its `_auth_data_<provider>` after the provider is later removed from config.
await reconfigureServer({ auth: { line: { clientId: 'x', clientSecret: 'y' } } });
const config = Config.get(Parse.applicationId);
const user = new Parse.User();
await user.save({ username: 'stale-line-user', password: 'pass' });
// Inject stale built-in-provider authData directly, bypassing auth validation — this
// reproduces a row created while `line` was still configured.
const staleAuthData = { id: 'stale-line-id', access_token: 'stale-token' };
await config.database.update(
'_User',
{ objectId: user.id },
{ authData: { line: staleAuthData } }
);

// Remove the provider from config. `line` is still a built-in adapter, so loadAuthAdapter
// reaches validateOptions with no options and throws during afterFind.
await reconfigureServer({ auth: {} });

// Full fetch (no keys selected) with the master key mirrors Parse Dashboard opening _User.
const fetched = new Parse.User();
fetched.id = user.id;
await expectAsync(fetched.fetch({ useMasterKey: true })).toBeResolved();
// Skip-and-keep-raw: the stale provider's authData is returned unchanged, not stripped.
expect(fetched.get('authData')).toEqual({ line: staleAuthData });
});
});
16 changes: 15 additions & 1 deletion src/Adapters/Auth/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import loadAdapter from '../AdapterLoader';
import Parse from 'parse/node';
import AuthAdapter from './AuthAdapter';
import { logger } from '../../logger';

const apple = require('./apple');
const digits = require('./twitter'); // digits tokens are validated by twitter
Expand Down Expand Up @@ -228,7 +229,20 @@ module.exports = function (authOptions = {}, enableAnonymousUsers = true) {
const adapters = Object.keys(authData);
await Promise.all(
adapters.map(async provider => {
const authAdapter = getValidatorForProvider(provider);
let authAdapter;
try {
authAdapter = getValidatorForProvider(provider);
} catch (e) {
// The adapter could not be resolved — typically a built-in code-auth provider such as
// `line`/`instagram` that was removed from config while a _User still carries stale
// `_auth_data_<provider>` (loadAuthAdapter throws from validateOptions when a built-in
// adapter has no options). Skip afterFind for this provider instead of failing the
// whole _User fetch, but log so a genuine adapter error is not silently swallowed. (#10526)
logger.warn(
`Skipping afterFind auth adapter for provider "${provider}": ${e.message || e}`
);
return;
}
if (!authAdapter) {
return;
}
Expand Down
Loading