Skip to content

fix: respect Shield's allowRegistration setting in OAuth callback - #200

Open
evansharp wants to merge 1 commit into
datamweb:developfrom
evansharp:fix/respect-shield-allow-registration
Open

evansharp wants to merge 1 commit into
datamweb:developfrom
evansharp:fix/respect-shield-allow-registration

Conversation

@evansharp

@evansharp evansharp commented Oct 18, 2026 •

Copy link
Copy Markdown

Summary

Shield OAuth creates accounts even when Shield's registration is turned off. OAuthController::callBack() registers any email it doesn't recognise and never checks Shield's Auth.allowRegistration setting. On an app that has disabled registration (public bool $allowRegistration = false; in app/Config/Auth.php, or auth.allowRegistration = false in .env), anyone can still sign up just by using an enabled OAuth button.

This PR makes the OAuth callback honour that setting and closes a related fail-open in the per-service check.

The problem

1. Shield's global registration switch is ignored

Before creating a user, the callback only looked at the service's own flag:

if (setting('ShieldOAuthConfig.oauthConfigs')[$oauthName]['allow_register'] === false) {

Shield's RegisterController blocks registration when setting('Auth.allowRegistration') is false, but OAuth goes around it. An admin who turns off registration in Shield would reasonably expect that to cover every way of creating an account.

2. The per-service check fails open

The check only blocks when allow_register is exactly false. If a service config has no allow_register key (a hand-written config for a custom provider, say), registration is allowed. When the key is missing, PHP also raises an "undefined array key" warning.

The fix

Two small private helpers in OAuthController, both run before any user record is written:

Helper Allows registration when Message when refused
isShieldRegistrationAllowed() setting('Auth.allowRegistration') === true Auth.registerDisabled (Shield's own message, same as its register page)
isOAuthRegistrationAllowed($oauthName) the service's allow_register is exactly true; a missing key counts as not allowed ShieldOAuthLang.Callback.account_not_found (unchanged)

Because it goes through setting(), the global check picks up the value from app/Config/Auth.php, .env overrides and the Settings database, just like Shield does.

I also added a short "Controlling Registration" section to docs/install.md explaining how the two settings work together.

Behaviour changes

  • Registration disabled in Shield: an OAuth login for an unknown email no longer creates an account. The user is redirected to logoutRedirect() with Shield's "registration is not allowed" message.
  • Existing users are unaffected: anyone who already has an account can still log in through OAuth when registration is off (as long as allow_login is true), just as Shield's password login keeps working.
  • Missing allow_register key: that service now refuses to create new accounts. The bundled GitHub and Google configs, the make:oauth generator template and the docs all set the key to true, so default setups behave the same as before.

How to test

  1. Set auth.allowRegistration = false in .env. Keep allow_register => true for GitHub/Google.
  2. Sign in with an OAuth account whose email has no Shield account.
    • Before: a new user is created and logged in.
    • After: you are redirected with "Registration is not currently allowed." and no row is added to users.
  3. Sign in through OAuth with an email that does have an account. You are still logged in.
  4. Set auth.allowRegistration = true again and repeat step 2. The account is created as before.
  5. Optional: remove allow_register from one service's config and repeat step 2. Registration through that service is refused.

Notes

  • This is independent of Add 'registration' event trigger from Shield into Oauth #196 (firing Shield's register event). Both PRs touch the same else branch in callBack(), but in different hunks, so they should merge cleanly in either order.
  • I haven't added automated tests, since the package doesn't have a test suite yet.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • OAuth no longer creates accounts unless both global registration and the selected service’s registration setting are enabled. When registration is unavailable, the OAuth callback reports an error; existing users can still log in if that service allows login.
  • Documentation
    • Clarified how global and service-specific settings control OAuth registration and login.

OAuthController::callBack() created a new user for any unknown email
returned by the OAuth provider, checking only the per-service
`allow_register` flag. It never consulted Shield's global
`Auth.allowRegistration` setting, so apps that disabled registration
in Shield (in app/Config/Auth.php or via `auth.allowRegistration =
false` in .env) could still have accounts created through any enabled
OAuth service.

The per-service check also failed open: it only blocked when
`allow_register` was strictly `false`, so a service config missing the
key permitted registration.

Changes:
- Add isShieldRegistrationAllowed(), which checks
  setting('Auth.allowRegistration') === true. When it is false the user
  is redirected with Shield's own `Auth.registerDisabled` message,
  matching Shield's RegisterController.
- Add isOAuthRegistrationAllowed(), which only allows registration when
  the service's `allow_register` is exactly `true` (fails closed when
  the key is missing).
- Both checks run before any user record is created. Existing users can
  still log in through OAuth; only new account creation is gated.
- Document how the two settings interact in docs/install.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3f525607-57d1-4312-9129-b00bd58d368a
📥 Commits

Reviewing files that changed from the base of the PR and between 82f07b6 and dd49b10.

📒 Files selected for processing: 2
  • docs/install.md
  • src/Controllers/OAuthController.php

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

OAuth account creation now requires Shield’s global Auth.allowRegistration setting and the selected service’s allow_register setting to be true. Existing users can still log in when registration is disabled if allow_login is true.

Changes: OAuth Registration Controls

Layer / File(s) Summary
Registration gating and documentation
src/Controllers/OAuthController.php, docs/install.md
The callback checks both registration settings before creating an account. It redirects when either check fails. The documentation describes the settings and existing-user login behavior.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Suggested reviewers: warcooft

Merge Risk: ⚪ Minimal · up to dd49b

New OAuth accounts require both registration settings to be enabled, while existing users can still sign in when the service allows login. No actionable merge risk is established by the reviewed changes.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 1 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: making the OAuth callback respect Shield's global Auth.allowRegistration setting.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 1 files. (1 skipped: 1 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant