{"record":{"id":"8525eebb1f571d8d","repo":"instructure/canvas-lms","slug":"user-is-from-unacceptable-domain-domain","errorCode":null,"errorMessage":"User is from unacceptable domain %{domain}.","messagePattern":"User is from unacceptable domain %(.+?)\\.","errorType":"validation","errorClass":"OAuthValidationError","httpStatus":null,"severity":"error","filePath":"app/models/authentication_provider/google.rb","lineNumber":82,"sourceCode":"      email\n      family_name\n      given_name\n      locale\n      name\n      sub\n    ].freeze\n  end\n\n  def unique_id(token)\n    id_token = claims(token)\n    if hosted_domain\n      if !id_token[\"hd\"]\n        # didn't make a \"nice\" exception for this, cause it should never happen.\n        # either we got MITM'ed (on the server side), or Google's docs lied;\n        # this check is just an extra precaution\n        raise \"Google Apps user not received, but required\"\n      elsif hosted_domain != \"*\" && !hosted_domains.include?(id_token[\"hd\"])\n        raise OAuthValidationError, t(\"User is from unacceptable domain %{domain}.\", domain: id_token[\"hd\"].inspect)\n      end\n    end\n    super\n  end\n\n  protected\n\n  def userinfo_endpoint\n    \"https://www.googleapis.com/oauth2/v3/userinfo\"\n  end\n\n  def client_options\n    super.merge(\n      auth_scheme: :basic_auth\n    )\n  end\n\n  def authorize_options","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/models/authentication_provider/google.rb#L64-L100","documentation":"AuthenticationProvider::Google#unique_id validates Google id_token hosted-domain (hd) claims for Google Apps/domain-restricted auth providers. If the provider's hosted_domain is not '*' and the token's hd is not in the allowed hosted_domains list, it raises OAuthValidationError 'User is from unacceptable domain \"...\".' This enforces that only members of the configured Google Workspace domain(s) can authenticate.","triggerScenarios":"A user authenticates with a personal gmail.com account (hd nil or 'gmail.com') against a provider configured with hosted_domain 'example.edu'; an alias/secondary Workspace domain not included in hosted_domains; user's domain changed in Google Admin after provider config; multiple hosted_domains configured but the token carries one not listed.","commonSituations":"Schools adding a new domain (students.school.edu) without updating the Canvas Google provider settings; SSO rollout where users use personal accounts; testing with non-domain accounts; typo in the configured hosted domain setting.","solutions":["Add the user's actual domain to the provider's hosted_domains list (Account > Authentication > Google provider settings)","Set hosted_domain to '*' if any Google account should be allowed","Have the user sign in with an account on the allowed domain (Google account chooser)","Ensure the Google OAuth client's hd parameter and Canvas config stay in sync after domain changes"],"exampleFix":"// before\nprovider.hosted_domains # ['example.edu'] but user hd is 'alumni.example.edu'\n// after\nprovider.update(hosted_domains: ['example.edu', 'alumni.example.edu']) # or '*'","handlingStrategy":"try-catch","validationCode":"// before initiating SSO, confirm account domain\ndomain = userEmail.split('@')[1];\nif (!allowedHostedDomains.includes(domain) && allowedHostedDomains[0] !== '*')\n  showError('Use your institution Google account');","typeGuard":"const isAllowedDomain = (hd, allowed) => allowed.includes('*') || allowed.includes(hd)","tryCatchPattern":"begin\n  unique_id = provider.unique_id(token)\nrescue OAuthValidationError => e\n  render login_page_with_error: e.message\nend","preventionTips":["Keep hosted_domains in the Google auth provider settings current (add new institutional domains)","Set hosted_domain '*' only when personal accounts are acceptable","Test SSO with both an in-domain and personal account before rollout","Sync the Google OAuth client hd hint with Canvas provider config"],"tags":["oauth","google","authentication","sso"],"backgroundTag":"oauth-domain-validation-failed","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}