Description
Statamic\OAuth\Provider persists the mapping between a provider account (e.g. a Google sub) and a Statamic user via getIds()/setIds(), which read/write a plain PHP file at storage_path("statamic/oauth/{$this->name}.php") (src/OAuth/Provider.php). This happens unconditionally — regardless of which user repository driver is configured.
That's a reasonable default for the flat-file user repository, where there's no database to lean on. But when config('statamic.users.repository') is eloquent, users/roles/groups already live in the database via Statamic\Auth\Eloquent\User/UserRepository. OAuth connections are the one piece of auth-related state still stuck on local disk in that setup.
In practice, storage_path() isn't durable in a lot of environments an Eloquent-driven app would run in — ephemeral compute, multiple app instances behind a load balancer, deploy pipelines that don't preserve arbitrary storage/ subpaths across releases. When that file is missing or not visible to the instance handling a request, findUser() returns null, handleProviderCallback() falls through to createUser(), discovers the email already taken, throws OAuthEmailExistsException, and the user is silently redirected to the unauthorized page — no exception logged, no visible error.
Suggested fix
Extend the existing driver-aware pattern (already used for users/roles/groups) to OAuth connections: when the eloquent repository is active, OAuth\Manager builds providers backed by an Eloquent-persisted connections table instead of the file.
We've built and tested this as a PR — happy to have it adjusted to fit core's preferred conventions.
Version
statamic/cms v6.26.0 (reproduced against latest 6.x as of this report too)
Description
Statamic\OAuth\Providerpersists the mapping between a provider account (e.g. a Googlesub) and a Statamic user viagetIds()/setIds(), which read/write a plain PHP file atstorage_path("statamic/oauth/{$this->name}.php")(src/OAuth/Provider.php). This happens unconditionally — regardless of which user repository driver is configured.That's a reasonable default for the flat-file user repository, where there's no database to lean on. But when
config('statamic.users.repository')iseloquent, users/roles/groups already live in the database viaStatamic\Auth\Eloquent\User/UserRepository. OAuth connections are the one piece of auth-related state still stuck on local disk in that setup.In practice,
storage_path()isn't durable in a lot of environments an Eloquent-driven app would run in — ephemeral compute, multiple app instances behind a load balancer, deploy pipelines that don't preserve arbitrarystorage/subpaths across releases. When that file is missing or not visible to the instance handling a request,findUser()returnsnull,handleProviderCallback()falls through tocreateUser(), discovers the email already taken, throwsOAuthEmailExistsException, and the user is silently redirected to the unauthorized page — no exception logged, no visible error.Suggested fix
Extend the existing driver-aware pattern (already used for users/roles/groups) to OAuth connections: when the
eloquentrepository is active,OAuth\Managerbuilds providers backed by an Eloquent-persisted connections table instead of the file.We've built and tested this as a PR — happy to have it adjusted to fit core's preferred conventions.
Version
statamic/cmsv6.26.0 (reproduced against latest6.xas of this report too)