{"record":{"id":"16c445a7bc1bcb9f","repo":"RocketChat/Rocket.Chat","slug":"service-not-configured","errorCode":null,"errorMessage":"Service not configured","messagePattern":"Service not configured","errorType":"exception","errorClass":"Accounts.ConfigError","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/auth-providers/custom-oauth/custom_oauth_server.js","lineNumber":120,"sourceCode":"\t\t}\n\n\t\tif (!isAbsoluteURL(this.identityPath)) {\n\t\t\tthis.identityPath = this.serverURL + this.identityPath;\n\t\t}\n\n\t\tif (this.emailPath && !isAbsoluteURL(this.emailPath)) {\n\t\t\tthis.emailPath = this.serverURL + this.emailPath;\n\t\t}\n\n\t\tif (Match.test(options.addAutopublishFields, Object)) {\n\t\t\tAccounts.addAutopublishFields(options.addAutopublishFields);\n\t\t}\n\t}\n\n\tasync getAccessToken(query) {\n\t\tconst config = await ServiceConfiguration.configurations.findOneAsync({ service: this.name });\n\t\tif (!config) {\n\t\t\tthrow new Accounts.ConfigError();\n\t\t}\n\n\t\tlet response = undefined;\n\n\t\tconst headers = {\n\t\t\t'Content-Type': 'application/x-www-form-urlencoded',\n\t\t\t'User-Agent': this.userAgent, // http://doc.gitlab.com/ce/api/users.html#Current-user\n\t\t\t'Accept': 'application/json',\n\t\t};\n\t\tconst params = new URLSearchParams({\n\t\t\tcode: query.code,\n\t\t\tredirect_uri: OAuth._redirectUri(this.name, config),\n\t\t\tgrant_type: 'authorization_code',\n\t\t\tstate: query.state,\n\t\t});\n\n\t\t// Only send clientID / secret once on header or payload.\n\t\tif (this.tokenSentVia === 'header') {","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/auth-providers/custom-oauth/custom_oauth_server.js#L102-L138","documentation":"getAccessToken() looks up the service's entry in the ServiceConfiguration.configurations MongoDB collection before exchanging the OAuth authorization code; when no document exists for { service: this.name }, Meteor's Accounts.ConfigError is thrown, whose rendered message is 'Service <name> not configured'. Constructing the CustomOAuth class (driven by settings at startup) does not create that document - it is written only when an admin saves the service's credentials.","triggerScenarios":"The OAuth callback /_oauth/<name> is hit while Client id/Secret for the service were never saved; the ServiceConfiguration document was deleted directly in Mongo; the service was disabled and its configuration row removed; the database was restored/migrated without the ServiceConfiguration collection.","commonSituations":"Moving to a new instance with the same settings but a fresh mongo; test suites that instantiate CustomOAuth without seeding mongo; admin typed the settings but never pressed Save; exact-name mismatch (case/whitespace) between the strategy name and the stored service field.","solutions":["Open Admin -> OAuth -> <custom service>, fill in Client id and Client Secret, and Save so the configuration document is (re)created","Verify the document exists: db.ServiceConfiguration.configurations.findOne({ service: '<name>' }) in mongo","Make sure the service is enabled (Accounts_OAuth_Custom-<name> = true) before users hit the login button","Check for exact-name mismatches (case, whitespace) between the strategy name and the stored service field"],"exampleFix":"// mongo shell: confirm/seed the config the strategy expects\nuse rocketchat\ndb.ServiceConfiguration.configurations.insertOne({\n  service: 'my-idp',\n  clientId: '<client-id>',\n  secret: '<client-secret>',\n  loginStyle: 'popup'\n})","handlingStrategy":"try-catch","validationCode":"// server-side health check before exposing the login button\nimport { ServiceConfiguration } from 'meteor/service-configuration';\n\nconst isServiceConfigured = async (name: string): Promise<boolean> =>\n  !!(await ServiceConfiguration.configurations.findOneAsync({ service: name }, { projection: { _id: 1 } }));\n\nif (!(await isServiceConfigured('my-idp'))) renderLoginButtonDisabled('SSO not configured');","typeGuard":null,"tryCatchPattern":"try {\n  await customOAuth.getAccessToken(query);\n} catch (error) {\n  if (error instanceof Accounts.ConfigError) {\n    throw new Meteor.Error('oauth-unconfigured', 'SSO service is not configured. Contact your administrator.');\n  }\n  throw error;\n}","preventionTips":["Treat the ServiceConfiguration collection as deployment state - back it up or seed it with the environment","Add a startup assertion that every enabled custom OAuth service has a configuration row","Never instantiate CustomOAuth in tests without seeding ServiceConfiguration","Re-save OAuth settings after restoring a database from another environment"],"tags":["oauth","meteor","service-configuration","custom-oauth","setup"],"backgroundTag":"oauth-service-not-configured","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}