{"record":{"id":"a98bf8aafdb043b2","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-user-a98bf8","errorCode":"error-invalid-user","errorMessage":"Invalid user","messagePattern":"Invalid user","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/auth/addOAuthService.ts","lineNumber":35,"sourceCode":"\tif ((await hasPermissionAsync(userId, 'add-oauth-service')) !== true) {\n\t\tthrow new Meteor.Error('error-action-not-allowed', 'Adding OAuth Services is not allowed', {\n\t\t\tmethod: 'addOAuthService',\n\t\t\taction: 'Adding_OAuth_Services',\n\t\t});\n\t}\n\n\tawait addOAuthService(name);\n};\n\nMeteor.methods<ServerMethods>({\n\tasync addOAuthService(name) {\n\t\tmethodDeprecationLogger.method('addOAuthService', '9.0.0', '/v1/settings.addCustomOAuth');\n\t\tcheck(name, String);\n\n\t\tconst userId = Meteor.userId();\n\n\t\tif (!userId) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'addOAuthService' });\n\t\t}\n\n\t\treturn addOAuthServiceMethod(userId, name);\n\t},\n});\n","sourceCodeStart":17,"sourceCodeEnd":41,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/auth/addOAuthService.ts#L17-L41","documentation":"The 'addOAuthService' DDP method resolves the caller via Meteor.userId(); a null value (anonymous connection or expired/revoked login token) throws error-invalid-user before the permission check runs. Standard unauthenticated-call guard; the method is deprecated in favor of POST /v1/settings.addCustomOAuth which authenticates via X-Auth-Token/X-User-Id headers.","triggerScenarios":"Meteor.call('addOAuthService', name) on a DDP connection without a valid login session; a resume token invalidated by logout-all while the socket stayed open; setup scripts driving DDP without ever logging in.","commonSituations":"Automation that opens a DDP socket but skips the Accounts login step; expired resume tokens in long-lived tooling; custom clients that bypass the login flow.","solutions":["Log in first (Meteor.loginWithToken or accounts login) and retry the method call.","Use POST /api/v1/settings.addCustomOAuth with an admin token for scripted OAuth setup.","Handle token expiry by re-authenticating instead of retrying blindly."],"exampleFix":"// before: anonymous DDP connection\nMeteor.call('addOAuthService', 'nextcloud');\n\n// after: authenticated REST call\nawait fetch('/api/v1/settings.addCustomOAuth', {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json', 'X-Auth-Token': authToken, 'X-User-Id': uid },\n  body: JSON.stringify({ name: 'nextcloud' }),\n});","handlingStrategy":"validation","validationCode":"const uid = Meteor.userId();\nif (!uid) {\n  await reauthenticate(); // login or loginWithToken before privileged method calls\n}\nMeteor.call('addOAuthService', name);","typeGuard":null,"tryCatchPattern":"try {\n  await Meteor.callAsync('addOAuthService', name);\n} catch (err: any) {\n  if (err?.error === 'error-invalid-user' && err?.details?.method === 'addOAuthService') {\n    await reauthenticate();\n    return Meteor.callAsync('addOAuthService', name);\n  }\n  throw err;\n}","preventionTips":["Complete the DDP login handshake before invoking admin methods.","Use REST with header auth for scripts; tokens are explicit and auditable.","Watch for logout-all / token revocation invalidating long-lived connections."],"tags":["authentication","meteor-methods","oauth","ddp"],"backgroundTag":"not-authenticated","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}