Skip to content

Migrate API controllers from check_for_auth_token to current_user#1469

Merged
scytacki merged 10 commits intomasterfrom
RIGSE-333-api-auth-unification
Mar 5, 2026
Merged

Migrate API controllers from check_for_auth_token to current_user#1469
scytacki merged 10 commits intomasterfrom
RIGSE-333-api-auth-unification

Conversation

@scytacki
Copy link
Member

@scytacki scytacki commented Mar 4, 2026

Summary

  • Add require_api_user! guard to API::APIController that returns JSON 401 for unauthenticated requests
  • Migrate BookmarksController, TeacherClassesController, ExternalActivitiesController, and OfferingsController#create_for_external_activity from check_for_auth_token / auth_teacher to Devise's current_user
  • Add characterization tests documenting auth behavior before and after migration
  • Guest/unauthenticated requests now return 401 (previously 400 or 403 depending on controller) for controllers using require_api_user!

Behavior Changes

Controller Old guest status New guest status
BookmarksController 400 401
TeacherClassesController 400 401
ExternalActivitiesController 403 401
OfferingsController (other actions) 403 (unchanged) 403 (unchanged)

Test Plan

  • All 120 controller specs pass (bookmarks, teacher_classes, external_activities, offerings)
  • All 4 related policy specs pass
  • Characterization tests verified against old code before migration
  • Each controller migrated and tested individually

🤖 Generated with Claude Code

scytacki and others added 7 commits March 4, 2026 19:17
…ration

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace check_auth/check_for_auth_token with before_action :require_api_user!
and current_user. Guest requests now return 401 instead of 400.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace auth_teacher/check_for_auth_token with before_action :require_api_user!
and :require_teacher!. Guest requests now return 401 instead of 400.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace check_for_auth_token with before_action :require_api_user! and
current_user. Guest requests now return 401 instead of 403.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rent_user

Remove check_for_auth_token call and use current_user directly.
Pundit authorize still handles guest rejection (403).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@scytacki scytacki changed the base branch from master to RIGSE-332-auth-logging March 4, 2026 19:47
- authenticate_user! → require_api_user! (CustomFailure redirect issue)
- Document per-controller details matching what was built
- Add status code summary table
- Mark status as Implemented

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@scytacki scytacki requested a review from Copilot March 4, 2026 19:54
Copy link

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

This PR migrates several API controllers away from check_for_auth_token to Devise’s current_user, standardizing unauthenticated handling via a new require_api_user! guard and updating specs/docs to reflect the new behavior.

Changes:

  • Add require_api_user! to API::APIController and apply it to selected controllers to return JSON 401 for unauthenticated requests.
  • Replace check_for_auth_token / auth_teacher usage with current_user in Bookmarks, TeacherClasses, ExternalActivities, and Offerings#create_for_external_activity.
  • Update/add controller specs and add design + caller research documentation for the migration.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
rails/app/controllers/api/api_controller.rb Introduces require_api_user! JSON 401 guard for API auth.
rails/app/controllers/api/v1/bookmarks_controller.rb Switches bookmarks auth helper to use current_user + adds guard.
rails/app/controllers/api/v1/teacher_classes_controller.rb Uses current_user, adds guards, and adds a teacher-only filter.
rails/app/controllers/api/v1/external_activities_controller.rb Removes token parsing blocks and enforces login via require_api_user!.
rails/app/controllers/api/v1/offerings_controller.rb Removes token parsing and uses current_user for teacher/admin checks.
rails/spec/controllers/api/v1/bookmarks_controller_spec.rb Adds characterization coverage for 401 guest + 400 non-teacher behavior.
rails/spec/controllers/api/v1/teacher_clazzes_controller_spec.rb Adds characterization for show guest/non-teacher + updates anonymous status expectations.
rails/spec/controllers/api/v1/external_activities_controller_spec.rb Updates guest expectations to 401 for endpoints now guarded by require_api_user!.
rails/spec/controllers/api/v1/offerings_controller_spec.rb Adds guest spec for create_for_external_activity (still 403 via Pundit).
docs/specs/2026-03-04-controller-migration-design.md Documents the migration approach and intended status-code behavior.
docs/specs/2026-03-04-controller-migration-caller-research.md Documents known callers and expected impact of status-code changes.
CLAUDE.md Adds guidance about running commands via Docker instead of host.

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

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +87 to +91
unless current_user
error('You must be logged in to use this endpoint', 401)
end
end

Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

require_api_user! renders an error but doesn’t explicitly halt the filter/action. While Rails often stops processing after render, it’s safer (and clearer) to return immediately (e.g., return error(...) unless current_user) to avoid any chance of subsequent filters/actions running and causing double-render or nil-access issues.

Suggested change
unless current_user
error('You must be logged in to use this endpoint', 401)
end
end
return error('You must be logged in to use this endpoint', 401) unless current_user
end

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

Both require_api_user! and require_teacher! are before_action callbacks. In Rails, calling render inside a before_action automatically halts the filter chain and prevents the action from executing — no explicit return is needed. This is standard Rails behavior (see ActionController filters docs). Adding return would be purely cosmetic.

Comment on lines +77 to +79
unless current_user.portal_teacher
error('You must be logged in as a teacher to use this endpoint')
end
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

require_teacher! should explicitly halt after rendering the error (e.g., return error(...) unless ...). This avoids any possibility of the action continuing after an error response, which can lead to double-render exceptions or follow-on failures.

Suggested change
unless current_user.portal_teacher
error('You must be logged in as a teacher to use this endpoint')
end
return error('You must be logged in as a teacher to use this endpoint') unless current_user.portal_teacher

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

Same as above — require_teacher! is a before_action, so render already halts the chain. No return needed.

Comment on lines +18 to +20
[:create, :update, :destroy, :sort].each do |method|
it "returns error for #{method}" do
post method, params: { id: 1, clazz_id: 1 }
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

These specs use post for :update and :destroy, which doesn’t match the real routes/verbs (PUT/PATCH for update, DELETE for destroy). Even though controller specs can still invoke the action, using the correct HTTP verbs makes the characterization tests more faithful and reduces the chance of missing verb-specific behavior (e.g., middleware, routing constraints).

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

These are controller specs (not request specs), so the HTTP verb is largely irrelevant — Rails invokes the action method directly regardless of the verb used. These are characterization tests verifying auth behavior, not routing. No change needed.


## Purpose

Section 6 Step 1 of the auth unification design calls for migrating four controllers from `check_for_auth_token` to `current_user`. This changes the HTTP status code for authentication failures from **400** to **403** on some actions (the `error()` helper defaults to 400; Pundit returns 403).
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

This statement doesn’t match the behavior described in the PR summary/diffs: several endpoints now return 401 for unauthenticated requests due to require_api_user!. Suggest updating this line (and any related summary wording) to reflect the actual outcomes (e.g., 400→401 for unauthenticated, and in some cases 403 remains via Pundit).

Suggested change
Section 6 Step 1 of the auth unification design calls for migrating four controllers from `check_for_auth_token` to `current_user`. This changes the HTTP status code for authentication failures from **400** to **403** on some actions (the `error()` helper defaults to 400; Pundit returns 403).
Section 6 Step 1 of the auth unification design calls for migrating four controllers from `check_for_auth_token` to `require_api_user!`/`current_user`. This changes the HTTP status code for unauthenticated requests from **400** (via the `error()` helper) to **401**, while authorization failures continue to return **403** on some actions via Pundit.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed — updated the summary line and all "400→403" references throughout the doc to correctly say "400→401".

Comment on lines +74 to +79
| Controller | Old guest status | New guest status |
|---|---|---|
| BookmarksController | 400 | 401 |
| TeacherClassesController | 400 | 401 |
| ExternalActivitiesController | 403 | 401 |
| OfferingsController (other actions) | 403 (unchanged) | 403 (unchanged) |
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The status-code table has an extra leading | on each row (|| ...), which can render incorrectly as an empty first column in Markdown. Consider changing each row to a single leading pipe (| ...) so it renders as a standard 3-column table.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

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

The table renders correctly — there are no double pipes. Each row has the standard | col1 | col2 | col3 | format. This appears to be a hallucination.

scytacki and others added 2 commits March 4, 2026 20:06
…ration

- Mark Step 1 (controller migration) as completed
- Update controller table to show current_user/require_api_user! usage
- Note that JwtController is now the sole consumer of check_for_auth_token
- Add reference to migration design doc and PR #1469

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change "400→403" to "400→401" throughout the document to match the
actual behavior of require_api_user! which returns 401.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@scytacki scytacki marked this pull request as ready for review March 4, 2026 20:34
@scytacki scytacki requested a review from dougmartin March 4, 2026 20:34
Base automatically changed from RIGSE-332-auth-logging to master March 4, 2026 22:20
Copy link
Member

@dougmartin dougmartin left a comment

Choose a reason for hiding this comment

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

Looks good 👍

@scytacki scytacki merged commit 399753c into master Mar 5, 2026
9 checks passed
@scytacki scytacki deleted the RIGSE-333-api-auth-unification branch March 5, 2026 13:57
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.

3 participants