{"record":{"id":"c89347b15950751f","repo":"RocketChat/Rocket.Chat","slug":"401","errorCode":"401","errorMessage":"no matching login attempt found","messagePattern":"no matching login attempt found","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/cas/loginHandler.ts","lineNumber":19,"sourceCode":"import { CredentialTokens, Users } from '@rocket.chat/models';\nimport { getObjectKeys, wrapExceptions } from '@rocket.chat/tools';\nimport { Accounts } from 'meteor/accounts-base';\nimport { Meteor } from 'meteor/meteor';\n\nimport { createNewUser } from './createNewUser';\nimport { findExistingCASUser } from './findExistingCASUser';\nimport { logger } from './logger';\nimport { settings } from '../../settings';\nimport { setRealName } from '../users/setRealName';\n\nexport const loginHandlerCAS = async (options: any): Promise<undefined | Accounts.LoginMethodResult> => {\n\tif (!settings.get('CAS_enabled') || !options.cas || typeof options.cas.credentialToken !== 'string') {\n\t\treturn undefined;\n\t}\n\n\tconst credentials = await CredentialTokens.removeNotExpiredById(options.cas.credentialToken);\n\tif (credentials === undefined || credentials === null) {\n\t\tthrow new Meteor.Error(Accounts.LoginCancelledError.numericError, 'no matching login attempt found');\n\t}\n\n\tconst result = credentials.userInfo;\n\tconst syncUserDataFieldMap = settings.get<string>('CAS_Sync_User_Data_FieldMap').trim();\n\tconst casVersion = parseFloat(settings.get('CAS_version') ?? '1.0');\n\tconst syncEnabled = settings.get('CAS_Sync_User_Data_Enabled');\n\tconst flagEmailAsVerified = settings.get<boolean>('Accounts_Verify_Email_For_External_Accounts');\n\tconst userCreationEnabled = settings.get('CAS_Creation_User_Enabled');\n\n\tconst { username, attributes: credentialsAttributes } = result as { username: string; attributes: Record<string, string[]> };\n\n\t// We have these\n\tconst externalAttributes: Record<string, string> = {\n\t\tusername,\n\t};\n\n\t// We need these\n\tconst internalAttributes: Record<string, string | undefined> = {","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/cas/loginHandler.ts#L1-L37","documentation":"During CAS login the handler consumes the one-time cas.credentialToken via CredentialTokens.removeNotExpiredById. If no matching, unexpired token document exists, it throws Meteor.Error with Accounts.LoginCancelledError.numericError (401) and the message 'no matching login attempt found' — the standard signal that the temporary credential for this login attempt is already gone.","triggerScenarios":"The CAS callback arrives with a credentialToken that was already consumed (page refresh, double callback submission), expired before the callback landed (slow IdP or network, clock skew), or never existed (stale/hand-crafted login URL).","commonSituations":"Users refreshing the CAS callback page; retrying a failed login from an old page; long gaps between CAS redirect and callback; servers with unsynchronized clocks; multiple tabs starting CAS logins at once.","solutions":["Go back to the login page and start the CAS login again to obtain a fresh credential token.","Never refresh, bookmark, or replay the CAS callback URL.","Check CAS service-ticket/token lifetimes on the IdP and reduce latency between redirect and callback.","Ensure ROOT_URL and the CAS service URL registered on the IdP match exactly, and that server clocks are NTP-synced."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"import { Accounts } from 'meteor/accounts-base';\n\ntry {\n  await Meteor.loginWithCAS(casToken);\n} catch (e) {\n  if (e instanceof Meteor.Error && e.error === Accounts.LoginCancelledError.numericError) {\n    // one-shot credential consumed/expired: send the user back to the login page for a fresh attempt\n  }\n  throw e;\n}","preventionTips":["Treat CAS credential tokens as one-shot: never refresh or replay the callback URL.","Start each login attempt from the login page so a fresh credentialToken is generated.","NTP-sync all servers and keep IdP ticket lifetimes comfortably above real redirect latency."],"tags":["cas","sso","login","oauth","rocket-chat"],"backgroundTag":"sso-credential-token-expired","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}