diff --git a/lib/workos.rb b/lib/workos.rb index ae959d5c..3708baad 100644 --- a/lib/workos.rb +++ b/lib/workos.rb @@ -87,6 +87,7 @@ def self.key autoload :APIError, 'workos/errors' autoload :AuthenticationError, 'workos/errors' autoload :InvalidRequestError, 'workos/errors' + autoload :ForbiddenRequestError, 'workos/errors' autoload :SignatureVerificationError, 'workos/errors' autoload :TimeoutError, 'workos/errors' autoload :NotFoundError, 'workos/errors' diff --git a/lib/workos/client.rb b/lib/workos/client.rb index 184856b2..40ac4ee6 100644 --- a/lib/workos/client.rb +++ b/lib/workos/client.rb @@ -109,6 +109,14 @@ def handle_error_response(response:) http_status: http_status, request_id: response['x-request-id'], ) + when 403 + raise ForbiddenRequestError.new( + message: json['message'], + http_status: http_status, + request_id: response['x-request-id'], + code: json['code'], + data: json, + ) when 404 raise NotFoundError.new( message: json['message'], diff --git a/lib/workos/errors.rb b/lib/workos/errors.rb index 37e86730..c7c2acd7 100644 --- a/lib/workos/errors.rb +++ b/lib/workos/errors.rb @@ -64,6 +64,10 @@ class AuthenticationError < WorkOSError; end # parameters. class InvalidRequestError < WorkOSError; end + # ForbiddenError is raised when a request is forbidden, likely due to missing a step + # (i.e. verifying email ownership before authenticating). + class ForbiddenRequestError < WorkOSError; end + # SignatureVerificationError is raised when the signature verification for a # webhook fails class SignatureVerificationError < WorkOSError; end diff --git a/spec/lib/workos/user_management_spec.rb b/spec/lib/workos/user_management_spec.rb index a7723cbb..c26ab5ba 100644 --- a/spec/lib/workos/user_management_spec.rb +++ b/spec/lib/workos/user_management_spec.rb @@ -404,6 +404,20 @@ end end end + + context 'with an unverified user' do + it 'raises a ForbiddenRequestError' do + VCR.use_cassette('user_management/authenticate_with_password/unverified') do + expect do + WorkOS::UserManagement.authenticate_with_password( + email: 'unverified@workos.app', + password: '7YtYic00VWcXatPb', + client_id: 'client_123', + ) + end.to raise_error(WorkOS::ForbiddenRequestError, /Email ownership must be verified before authentication/) + end + end + end end describe '.authenticate_with_code' do diff --git a/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_password/unverified.yml b/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_password/unverified.yml new file mode 100644 index 00000000..aa2fc1f5 --- /dev/null +++ b/spec/support/fixtures/vcr_cassettes/user_management/authenticate_with_password/unverified.yml @@ -0,0 +1,82 @@ +--- +http_interactions: + - request: + method: post + uri: https://api.workos.com/user_management/authenticate + body: + encoding: UTF-8 + string: + '{"client_id":"client_123","client_secret":"","email":"unverified@workos.app","password":"7YtYic00VWcXatPb","ip_address":"200.240.210.16","user_agent":"Mozilla/5.0 + (Macintosh; Intel Mac OS X 10_15_7) Chrome/108.0.0.0 Safari/537.36","grant_type":"password"}' + headers: + Content-Type: + - application/json + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - '*/*' + User-Agent: + - WorkOS; ruby/3.0.2; arm64-darwin21; v2.16.0 + response: + status: + code: 403 + message: Email ownership must be verified before authentication. + headers: + Date: + - Tue, 29 Aug 2023 00:24:25 GMT + Content-Type: + - application/json; charset=utf-8 + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Cf-Ray: + - 7fe0a6a27b0bc39c-SEA + Cf-Cache-Status: + - DYNAMIC + Etag: + - W/"16e-hoaHaR0EhmAH7TaNBOF8B2OHJq4" + Strict-Transport-Security: + - max-age=15552000; includeSubDomains + Vary: + - Origin, Accept-Encoding + Via: + - 1.1 spaces-router (devel) + Access-Control-Allow-Credentials: + - 'true' + Content-Security-Policy: + - "default-src 'self';base-uri 'self';block-all-mixed-content;font-src 'self' + https: data:;frame-ancestors 'self';img-src 'self' data:;object-src 'none';script-src + 'self';script-src-attr 'none';style-src 'self' https: 'unsafe-inline';upgrade-insecure-requests" + Expect-Ct: + - max-age=0 + Referrer-Policy: + - no-referrer + X-Content-Type-Options: + - nosniff + X-Dns-Prefetch-Control: + - 'off' + X-Download-Options: + - noopen + X-Frame-Options: + - SAMEORIGIN + X-Permitted-Cross-Domain-Policies: + - none + X-Request-Id: + - 62990367-ddaf-46b3-a32f-38fc4f29d581 + X-Xss-Protection: + - '0' + Set-Cookie: + - __cf_bm=IiwoT1XAlPdVWj334oRTocU7zZyvKgYw61o0UoA7GtE-1693268665-0-AZTn/iGDfGV6R5j3aj7lcPod7FB9P3cbHc9pD1oN/U5ZmnUYvpCecp6AL+8p/+/bMuwwGqXGNMSa/eIpa0TVm+I=; + path=/; expires=Tue, 29-Aug-23 00:54:25 GMT; domain=.workos.com; HttpOnly; + Secure; SameSite=None + - __cfruid=beafd87202de7b7d34fd4a1af55696cb5d19364d-1693268665; path=/; domain=.workos.com; + HttpOnly; Secure; SameSite=None + Server: + - cloudflare + body: + encoding: ASCII-8BIT + string: '{"code":"email_verification_required", "message":"Email ownership must be verified before authentication.", "email":"unverified@workos.app", "pending_authentication_token":"RWx94aFHwanPOebv7tKbBkJm0", "email_verification_id":"email_verification_01JG43A0WYAFAPHMNBV5XF2R4M"}' + http_version: + recorded_at: Tue, 29 Aug 2023 00:24:25 GMT +recorded_with: VCR 5.0.0