Skip to content

feat: add Device Authorization Flow to the Authentication API - #794

Open
gagalago wants to merge 1 commit into
auth0:masterfrom
gagalago:feat/device-authorization-flow
Open

feat: add Device Authorization Flow to the Authentication API#794
gagalago wants to merge 1 commit into
auth0:masterfrom
gagalago:feat/device-authorization-flow

Conversation

@gagalago

Copy link
Copy Markdown

Changes

Implements the Device Authorization Flow in Auth0::Api::AuthenticationEndpoints. This is the proposal from #792, opened as a pull request per the general contributing guidelines ("PRs to our libraries are always welcome"); happy to close it if you would rather settle the design on the issue first.

Two new methods, additive only — no existing method, endpoint or signature changes:

  • start_device_flow(scope:, audience:, client_id:)POST /oauth/device/code, returning the parsed body (device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval).
  • exchange_device_code_for_tokens(device_code, client_id:)POST /oauth/token with grant_type=urn:ietf:params:oauth:grant-type:device_code, returning an Auth0::AccessToken.

They are named after the existing start_passwordless_sms_flow / exchange_sms_otp_for_tokens pair so they read like their neighbours, and they follow the conventions already in the file: an Auth0::InvalidParameter guard on the required positional argument, a request_params hash, request_with_retry, and ::Auth0::AccessToken.from_response for the token response.

Note this is unrelated to Auth0::Api::V2::DeviceCredentials, which is the Management API device-credentials resource.

No new exception classes. While the user completes their part, Auth0 answers with an HTTP error whose body carries an error of authorization_pending or slow_down. Mixins::HTTPProxy#request already raises Auth0::HTTPError subclasses with the raw response body as the message — AccessDenied for 403 and BadRequest for 400, both HTTPError — so callers can distinguish the polling states with what is already there. A documented accessor for that error code would be a good follow-up, but it is deliberately not in this pull request.

References

For prior art inside the SDK family, Auth0.NET exposes the same two operations as StartDeviceFlowAsync(DeviceCodeRequest) and GetTokenAsync(DeviceCodeTokenRequest) on IAuthenticationApiClient.

Motivation: we run a small Rails service that acts as an OAuth proxy for our command-line client. It starts the flow, hands user_code and verification_uri to the CLI, and polls for the token. With this in place we can delete the hand-written Faraday client that exists only because the flow is not reachable from this SDK.

Testing

Three cases added to test/unit/authentication_endpoints_test.rb, alongside the existing ones and using the same WebMock body-matching style:

  • test_start_device_flow_requests_a_device_code — asserts client_id, scope and audience are sent to /oauth/device/code, and that the response fields come back
  • test_exchange_device_code_for_tokens — asserts the urn:ietf:params:oauth:grant-type:device_code grant type and device_code are sent, and that an Auth0::AccessToken is returned
  • test_exchange_device_code_for_tokens_raises_on_empty — the InvalidParameter guard
bundle exec rake test TEST=test/unit/authentication_endpoints_test.rb TESTOPTS="--name=/device_code|start_device_flow/"

I checked the tests are not vacuous: pointing start_device_flow at a different path makes its test fail, and restoring it makes it pass again.

Ruby full suite
3.3.9 555 runs, 4585 assertions, 0 failures, 0 errors
4.0.6 555 runs, 0 failures, 1 error — the pre-existing CGI.parse failure on master, unrelated to this change and fixed by #793

The three new tests pass on both (3 runs, 7 assertions, 0 failures).

bundle exec rubocop --force-exclusion reports no offences on the changed files. As with the rest of authentication_endpoints.rb, I followed the file's single-quoted style — it is listed under AllCops.Exclude in .rubocop.yml as ported verbatim from the legacy SDK.

Documentation

Added a Device Authorization Flow section to EXAMPLES.md, showing the full loop: start the flow, display the user code, poll on the returned interval, and treat authorization_pending / slow_down as continue-conditions.

  • This change adds unit test coverage
  • This change adds integration test coverage
  • This change has been tested on the latest version of Ruby

Checklist

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