Repository navigation
Make configured options reach LINE and harden the outbound calls - #4
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves the OmniAuth::Strategies::Line OAuth2 strategy so configured LINE authorize options actually reach the authorize URL, callback/redirect handling respects explicit configuration, and outbound token/verify/profile calls are more robust (timeouts + best-effort email). It also adds VCR-backed specs/cassettes to lock behavior to real LINE API responses.
Changes:
- Forward LINE-specific authorize parameters by expanding
authorize_options, and honoroptions[:redirect_uri]incallback_url. - Harden outbound calls: pin token exchange to
auth_scheme: :request_body, add verify timeouts + best-effort email degradation, and mapOAuth2::TimeoutErrortoTimeout::Error. - Add VCR configuration + recorded cassettes/specs for real-world LINE API error shapes.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
lib/omniauth/strategies/line.rb |
Adds authorize-option forwarding, redirect override, token auth scheme pinning, verify timeouts, and email degradation/logging. |
spec/spec_helper.rb |
Introduces VCR configuration to support cassette replay/recording in specs. |
spec/omniauth/strategies/line_spec.rb |
Expands specs for authorize params, redirect_uri behavior, timeout mapping, email degradation, and VCR-based API-shape assertions. |
spec/cassettes/verify_invalid_id_token.yml |
Records LINE verify endpoint rejection behavior. |
spec/cassettes/profile_invalid_access_token.yml |
Records LINE profile endpoint rejection behavior. |
spec/cassettes/token_invalid_client.yml |
Records LINE token endpoint rejection behavior. |
Gemfile |
Adds vcr to the test dependency group. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
spec/cassettes/verify_invalid_id_token.yml:52
- This cassette’s response body is marked
application/jsonbut the stored JSON contains a literal newline inside a quoted string, which makes it invalid JSON on replay. That forces the strategy down theJSON::ParserErrorpath and prevents logging the actualerror_descriptionfor this case.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
lib/omniauth/strategies/line.rb:78
emailparses the verify response withJSON.parse(response.body)without guarding against a nil/invalid body.Net::HTTPResponse#bodycan benil(or otherwise non-string), which raisesTypeErrorand would break the intended “best-effort” email behavior by failing the callback instead of degrading tonil. Coerce to string and rescueTypeErroralongsideJSON::ParserError.
e4ff49d to
8b9545a
Compare
|
Rebased this branch onto #6 ( Once #6 merges into |
8b9545a to
87044d4
Compare
omniauth-oauth2 only forwards options named in authorize_options (default scope/state) to the authorize URL, so prompt, bot_prompt, ui_locales and every other LINE parameter set on the strategy was silently dropped. Claude-Session: https://claude.ai/code/session_01RBRHMr4tD5hZ5Js6WQSHr5
Apps that compute their callback URL (multi-host setups resolving the tenant from the request) set options[:redirect_uri], which the previous callback_url override ignored in favor of the request host. Claude-Session: https://claude.ai/code/session_01RBRHMr4tD5hZ5Js6WQSHr5
- Pin the token exchange to client_secret_post: LINE documents only body credentials; the oauth2 gem's basic-auth default happens to work today but is undocumented LINE behavior. - Give the id-token verify call explicit open/read timeouts and degrade email to nil (with a logged warning) on timeout, rejection, or a non-JSON body instead of failing the whole login. - Map OAuth2::TimeoutError from the profile call to ::Timeout::Error so omniauth-oauth2's callback_phase turns it into fail!(:timeout) rather than a 500. Claude-Session: https://claude.ai/code/session_01RBRHMr4tD5hZ5Js6WQSHr5
Cassettes under spec/cassettes were recorded once against the real LINE API using throwaway credentials (no secrets involved) and are replayed from then on, locking the suite to LINE's actual error shapes for the token, verify, and profile endpoints. record: :once re-records only when a cassette file is deleted; CI never hits the network. Claude-Session: https://claude.ai/code/session_01RBRHMr4tD5hZ5Js6WQSHr5
filter_sensitive_data scrubs the channel secret from future recordings (the committed cassette is scrubbed retroactively), and record: :none on CI turns a missing cassette into a hard failure instead of a live call. Claude-Session: https://claude.ai/code/session_01RBRHMr4tD5hZ5Js6WQSHr5
87044d4 to
2133259
Compare
Summary
Four fixes, each with specs; suite stays at 100% line coverage (32 examples).
authorize_options(default: scope/state), soprompt,bot_prompt,ui_locales,nonce, and every other LINE parameter set on the strategy was silently dropped before it ever reached the authorize URL.prompt: 'consent'starts showing the consent screen).redirect_uri. Multi-host apps that compute their callback URL setoptions[:redirect_uri]; the previouscallback_urloverride ignored it in favor of the request host.auth_scheme: :request_body— LINE documents only body credentials; the oauth2 gem's basic-auth default happens to work but was verified to be undocumented LINE behavior. The id-token verify call gets explicit open/read timeouts (5s/10s, configurable viaverify_options) and degrades email tonilwith a logged warning on timeout, rejection, or a non-JSON body, instead of holding the login hostage or failing it.OAuth2::TimeoutErrorfrom the profile call (a Faraday subclass that omniauth-oauth2's callback_phase would let escape as a 500) is mapped to::Timeout::Errorso it becomesfail!(:timeout).spec/cassettes/locks the suite to LINE's actual error shapes for the token, verify, and profile endpoints. Recorded once with throwaway credentials (no secrets in the cassettes); CI only replays. Delete a cassette file to re-record.Verification
bundle exec rake: 32 examples, 0 failures, 100% line coverage.api.line.me(numeric client_id via Basic →invalid_grant, proving Basic is parsed; the pin to:request_bodyis about matching documented behavior, not fixing an outage).https://claude.ai/code/session_01RBRHMr4tD5hZ5Js6WQSHr5