Skip to content

Comments

Support multiple authentication options (GitHub, Google, Username-only)#33

Open
Copilot wants to merge 4 commits intomainfrom
copilot/support-multiple-authentication-options
Open

Support multiple authentication options (GitHub, Google, Username-only)#33
Copilot wants to merge 4 commits intomainfrom
copilot/support-multiple-authentication-options

Conversation

Copy link
Contributor

Copilot AI commented Feb 18, 2026

Add flexible authentication via GitHub OAuth, Google OAuth, or traditional username/password with optional email. Hide Django admin from app navigation.

Changes

  • OAuth integration: Add django-allauth[socialaccount] with GitHub and Google social providers. Credentials configured via env vars (GITHUB_OAUTH_CLIENT_ID, GOOGLE_OAUTH_CLIENT_ID, etc.)
  • Conditional provider enablement: OAuth providers are only configured when their env vars are set. OAuth buttons on login/register pages are hidden when credentials are absent, preventing broken OAuth flows.
  • Optional email registration: Custom RegistrationForm makes email optional with clear warning about password recovery implications
  • UI updates: Login and register pages conditionally show OAuth buttons with visual separator before traditional form. Admin link removed from nav (still at /admin/)
  • URL routing fix: Moved staff feedback URLs from admin/feedback/... to staff/feedback/... to avoid conflict with Django admin's catch-all URL handler
  • Tests: 19 tests covering form validation, conditional OAuth button rendering, email warning, admin link hiding, and feedback URL routing

Configuration

OAuth providers are only enabled when both client_id and secret env vars are present. Missing or empty values disable the provider and hide its button:

SOCIALACCOUNT_PROVIDERS = {}

if os.getenv('GITHUB_OAUTH_CLIENT_ID') and os.getenv('GITHUB_OAUTH_SECRET'):
    SOCIALACCOUNT_PROVIDERS['github'] = { ... }

if os.getenv('GOOGLE_OAUTH_CLIENT_ID') and os.getenv('GOOGLE_OAUTH_SECRET'):
    SOCIALACCOUNT_PROVIDERS['google'] = { ... }

Screenshots

Login page (no OAuth configured):
Login without OAuth

Login page (OAuth configured):
Login page with OAuth buttons

Register page (OAuth configured):
Register page with OAuth and email warning

Security Summary: CodeQL scan found 0 alerts. No vulnerabilities introduced.

Original prompt

This section details on the original issue you should resolve

<issue_title>Support multiple authentication options (GitHub, Google, Username-only)</issue_title>
<issue_description>Summary:
Introduce flexible authentication to allow users to sign in or register via GitHub OAuth, Google OAuth, or traditional username/password (with optional email).

Acceptance Criteria:

  • Add "Sign in with GitHub" and "Sign in with Google" (OAuth-based) as authentication options.
  • Update traditional registration flow: make email optional with a clear warning if omitted ("no password recovery if email not provided").
  • Provide clear UI to communicate risks/options.
  • Ensure users can manage accounts with minimum liability for email/PPI.
  • Keep Django admin only accessible via direct URL, hidden from main app navigation.

Rationale:

  • Improves user privacy and choice.
  • Reduces password/data breach liability for operators.
  • Matches best practices in modern authentication experiences.

Label: enhancement</issue_description>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…ion, hide admin nav

- Add django-allauth for GitHub and Google OAuth authentication
- Create custom RegistrationForm with optional email field and recovery warning
- Update login/register templates with OAuth buttons and clear UI sections
- Remove Django admin link from navigation (still accessible via /admin/ URL)
- Update home page to link to course creation instead of admin
- Configure allauth settings, backends, middleware in settings.py
- Add OAuth credential placeholders to .env.example
- Add 16 new tests covering auth forms, views, OAuth buttons, admin visibility

Co-authored-by: coreysreid <111491611+coreysreid@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for multiple authentication options Support multiple authentication options (GitHub, Google, Username-only) Feb 18, 2026
Copilot AI requested a review from coreysreid February 18, 2026 02:59
@coreysreid
Copy link
Owner

@copilot we had some CI tests fail can you sort this out

…dependency

The socialaccount providers (GitHub, Google OAuth) require the `requests`
library which is only included when installing with the [socialaccount]
extras specifier.

Co-authored-by: coreysreid <111491611+coreysreid@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot we had some CI tests fail can you sort this out

The CI failure was ModuleNotFoundError: No module named 'requests' — the base django-allauth package doesn't include requests, which is needed by the OAuth2/socialaccount providers. Fixed in 5f308c2 by changing django-allauth>=65.0.0 to django-allauth[socialaccount]>=65.0.0 in requirements.txt.

@coreysreid coreysreid marked this pull request as ready for review February 19, 2026 01:27
Copilot AI review requested due to automatic review settings February 19, 2026 01:27
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds multi-option authentication (GitHub OAuth, Google OAuth, and username/password with optional email) using django-allauth, updates the UI to surface OAuth entry points, and introduces tests covering the new auth UX and registration behavior.

Changes:

  • Add and configure django-allauth (apps, middleware, backends, provider config) and route /accounts/ to allauth.
  • Introduce a custom RegistrationForm with optional email + warning messaging; update register flow to use it.
  • Update login/register templates to include OAuth buttons; hide the Django admin link from navigation; add tests for these behaviors.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
study_platform/urls.py Adds allauth URL include under /accounts/.
study_platform/settings.py Enables allauth + providers and configures auth-related settings.
study/views.py Switches registration to use the custom RegistrationForm.
study/test_auth.py Adds test coverage for optional-email registration, OAuth button presence, and admin link hiding.
study/templates/study/register.html Adds social sign-up buttons and an email-omission warning.
study/templates/study/login.html Adds social sign-in buttons and keeps username/password login section.
study/templates/study/home.html Replaces admin “Manage Content” CTA with “Create Course”.
study/templates/study/base.html Removes Django admin link from the main navigation.
study/forms.py Adds RegistrationForm with optional email + help text.
requirements.txt Adds django-allauth[socialaccount] dependency.
.env.example Adds OAuth credential placeholders for GitHub/Google.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 203 to 218
SOCIALACCOUNT_PROVIDERS = {
'github': {
'APP': {
'client_id': os.getenv('GITHUB_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GITHUB_OAUTH_SECRET', ''),
},
'SCOPE': ['read:user'],
},
'google': {
'APP': {
'client_id': os.getenv('GOOGLE_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GOOGLE_OAUTH_SECRET', ''),
},
'SCOPE': ['profile'],
},
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub OAuth is configured even when env vars are missing (defaulting to empty strings). If credentials are intentionally unset, this should be treated as “provider disabled” (e.g., don’t include the provider config / don’t render the button) to avoid a broken OAuth flow.

Suggested change
SOCIALACCOUNT_PROVIDERS = {
'github': {
'APP': {
'client_id': os.getenv('GITHUB_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GITHUB_OAUTH_SECRET', ''),
},
'SCOPE': ['read:user'],
},
'google': {
'APP': {
'client_id': os.getenv('GOOGLE_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GOOGLE_OAUTH_SECRET', ''),
},
'SCOPE': ['profile'],
},
}
# Only configure social providers when credentials are present,
# so that missing env vars effectively disable the provider.
github_client_id = os.getenv('GITHUB_OAUTH_CLIENT_ID')
github_secret = os.getenv('GITHUB_OAUTH_SECRET')
google_client_id = os.getenv('GOOGLE_OAUTH_CLIENT_ID')
google_secret = os.getenv('GOOGLE_OAUTH_SECRET')
SOCIALACCOUNT_PROVIDERS = {}
if github_client_id and github_secret:
SOCIALACCOUNT_PROVIDERS['github'] = {
'APP': {
'client_id': github_client_id,
'secret': github_secret,
},
'SCOPE': ['read:user'],
}
if google_client_id and google_secret:
SOCIALACCOUNT_PROVIDERS['google'] = {
'APP': {
'client_id': google_client_id,
'secret': google_secret,
},
'SCOPE': ['profile'],
}

Copilot uses AI. Check for mistakes.
Comment on lines 203 to 218
SOCIALACCOUNT_PROVIDERS = {
'github': {
'APP': {
'client_id': os.getenv('GITHUB_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GITHUB_OAUTH_SECRET', ''),
},
'SCOPE': ['read:user'],
},
'google': {
'APP': {
'client_id': os.getenv('GOOGLE_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GOOGLE_OAUTH_SECRET', ''),
},
'SCOPE': ['profile'],
},
}
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Google OAuth is configured even when env vars are missing (defaulting to empty strings). If credentials are intentionally unset, this should be treated as “provider disabled” (e.g., don’t include the provider config / don’t render the button) to avoid a broken OAuth flow.

Suggested change
SOCIALACCOUNT_PROVIDERS = {
'github': {
'APP': {
'client_id': os.getenv('GITHUB_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GITHUB_OAUTH_SECRET', ''),
},
'SCOPE': ['read:user'],
},
'google': {
'APP': {
'client_id': os.getenv('GOOGLE_OAUTH_CLIENT_ID', ''),
'secret': os.getenv('GOOGLE_OAUTH_SECRET', ''),
},
'SCOPE': ['profile'],
},
}
# Read OAuth credentials without defaulting to empty strings so that
# missing values can be treated as "provider disabled".
GITHUB_OAUTH_CLIENT_ID = os.getenv('GITHUB_OAUTH_CLIENT_ID')
GITHUB_OAUTH_SECRET = os.getenv('GITHUB_OAUTH_SECRET')
GOOGLE_OAUTH_CLIENT_ID = os.getenv('GOOGLE_OAUTH_CLIENT_ID')
GOOGLE_OAUTH_SECRET = os.getenv('GOOGLE_OAUTH_SECRET')
SOCIALACCOUNT_PROVIDERS = {}
if GITHUB_OAUTH_CLIENT_ID and GITHUB_OAUTH_SECRET:
SOCIALACCOUNT_PROVIDERS['github'] = {
'APP': {
'client_id': GITHUB_OAUTH_CLIENT_ID,
'secret': GITHUB_OAUTH_SECRET,
},
'SCOPE': ['read:user'],
}
if GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_SECRET:
SOCIALACCOUNT_PROVIDERS['google'] = {
'APP': {
'client_id': GOOGLE_OAUTH_CLIENT_ID,
'secret': GOOGLE_OAUTH_SECRET,
},
'SCOPE': ['profile'],
}

Copilot uses AI. Check for mistakes.
Comment on lines 14 to 18
<a href="{% provider_login_url 'github' %}" class="btn" style="display: flex; align-items: center; justify-content: center; gap: 0.5rem; background: #24292e; color: white; text-decoration: none; padding: 0.75rem; border-radius: 5px;">
<svg height="20" width="20" viewBox="0 0 16 16" fill="white"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
Sign in with GitHub
</a>
<a href="{% provider_login_url 'google' %}" class="btn" style="display: flex; align-items: center; justify-content: center; gap: 0.5rem; background: #4285f4; color: white; text-decoration: none; padding: 0.75rem; border-radius: 5px;">
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These OAuth buttons are rendered unconditionally. If a provider is not configured/enabled, the link should be hidden (or replaced with disabled UI) to avoid sending users into a failing OAuth flow.

Copilot uses AI. Check for mistakes.
@@ -21,6 +21,7 @@

urlpatterns = [
path('admin/', admin.site.urls),
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The root URLConf mounts Django admin at the /admin/ prefix, but the study app also defines routes under /admin/feedback/... (admin_feedback_review/update_feedback_status). Requests to /admin/feedback/... will be captured by admin.site.urls first, making those study routes unreachable. Consider moving the study feedback URLs out of the /admin/ prefix (e.g., /staff/feedback/...) or mounting Django admin under a different prefix (e.g., /django-admin/) and updating links/tests accordingly.

Suggested change
path('admin/', admin.site.urls),
path('django-admin/', admin.site.urls),

Copilot uses AI. Check for mistakes.
Comment on lines 14 to 18
<a href="{% provider_login_url 'github' %}" class="btn" style="display: flex; align-items: center; justify-content: center; gap: 0.5rem; background: #24292e; color: white; text-decoration: none; padding: 0.75rem; border-radius: 5px;">
<svg height="20" width="20" viewBox="0 0 16 16" fill="white"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
Sign up with GitHub
</a>
<a href="{% provider_login_url 'google' %}" class="btn" style="display: flex; align-items: center; justify-content: center; gap: 0.5rem; background: #4285f4; color: white; text-decoration: none; padding: 0.75rem; border-radius: 5px;">
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These OAuth sign-up buttons are rendered unconditionally. If a provider is not configured/enabled, the link should be hidden (or replaced with disabled UI) to avoid sending users into a failing OAuth flow.

Copilot uses AI. Check for mistakes.
.env.example Outdated
ALLOWED_HOSTS=localhost,127.0.0.1
GITHUB_REPO=owner/repo-name

# OAuth providers (optional - leave empty to disable)
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment says OAuth credentials can be left empty to “disable” providers, but the app still renders provider buttons and configures the providers regardless. Either remove/adjust this guidance, or implement conditional provider enablement + conditional button rendering when credentials are present.

Suggested change
# OAuth providers (optional - leave empty to disable)
# OAuth providers (optional - set these only if you plan to use them)

Copilot uses AI. Check for mistakes.
@coreysreid
Copy link
Owner

@copilot apply changes based on the comments in this thread

- Only configure SOCIALACCOUNT_PROVIDERS when env vars are present
- Add oauth_providers context processor for template conditionals
- Conditionally render OAuth buttons on login/register pages
- Move feedback URLs from admin/feedback/ to staff/feedback/ to fix
  Django admin catch-all routing conflict
- Update .env.example comment
- Update tests: conditional OAuth visibility, feedback URL routing

Co-authored-by: coreysreid <111491611+coreysreid@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot apply changes based on the comments in this thread

Applied all 6 review comments in 4f6ad7f:

  1. Conditional OAuth configSOCIALACCOUNT_PROVIDERS is now built only when env vars are present (empty = provider disabled)
  2. Conditional OAuth buttons — Login and register templates only render OAuth buttons when the corresponding provider is configured, via a new oauth_providers context processor
  3. URL routing conflict — Moved admin/feedback/review/staff/feedback/review/ so Django admin's catch-all no longer intercepts it
  4. .env.example comment — Updated to "set these only if you plan to use them"
  5. Tests updated — 19 auth tests covering both configured and unconfigured OAuth states, plus feedback URL routing

Login page when no OAuth credentials are set:
Login without OAuth

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.

Support multiple authentication options (GitHub, Google, Username-only)

2 participants