RocketChat/Rocket.Chat · error · Meteor.Error

error-invalid-state

error-invalid-state

Error message

Invalid state provided

What it means

finishOAuthAuthorization is the last leg of the cloud OAuth flow. It compares the returned state parameter against the Cloud_Workspace_Registration_State setting stored when the flow started; a mismatch throws Meteor.Error 'error-invalid-state' — the standard OAuth CSRF state check failing for cloud registration.

Source

Thrown at apps/meteor/server/lib/cloud/finishOAuthAuthorization.ts:15

import { Users } from '@rocket.chat/models';
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
import { Meteor } from 'meteor/meteor';

import { getRedirectUri } from './getRedirectUri';
import { userScopes } from './oauthScopes';
import { assertNotOfflineLicense } from './offlineLicense';
import { settings } from '../../settings';
import { SystemLogger } from '../logger/system';

export async function finishOAuthAuthorization(code: string, state: string) {
	assertNotOfflineLicense();

	if (settings.get<string>('Cloud_Workspace_Registration_State') !== state) {
		throw new Meteor.Error('error-invalid-state', 'Invalid state provided', {
			method: 'cloud:finishOAuthAuthorization',
		});
	}

	const clientId = settings.get<string>('Cloud_Workspace_Client_Id');
	const clientSecret = settings.get<string>('Cloud_Workspace_Client_Secret');

	const scope = userScopes.join(' ');

	let payload;
	try {
		const cloudUrl = settings.get<string>('Cloud_Url');
		const response = await fetch(`${cloudUrl}/api/oauth/token`, {
			method: 'POST',
			headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
			params: new URLSearchParams({
				client_id: clientId,
				client_secret: clientSecret,

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Restart the cloud registration from the Setup Wizard / Admin > Cloud so a fresh state is generated end-to-end.
  2. Ensure only one registration flow runs at a time on the workspace.
  3. Never bookmark or replay the OAuth callback URL.
Defensive patterns

Strategy: retry

Try / catch

try {
  await Meteor.callAsync('cloud:finishOAuthAuthorization', code, state);
} catch (e) {
  if (e instanceof Meteor.Error && e.error === 'error-invalid-state') {
    // flow state stale/overwritten: restart registration from Admin > Cloud to mint a new state
  }
  throw e;
}

Prevention

When it happens

Trigger: The cloud:finishOAuthAuthorization callback arrives with a state from an earlier or different registration flow: a second admin started a new flow (overwriting the setting), the callback URL was replayed, or the setting was reset mid-flow.

Common situations: Two people (or two tabs) running workspace registration simultaneously; a stale browser tab completing an old OAuth redirect; reusing an old callback link after a failed attempt.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/94070ee86c46f342. Report an issue: GitHub.