Skip to content

Commit de4e23c

Browse files
authored
Fix SSO error handling to surface detailed validation errors (#385)
1 parent ffb578e commit de4e23c

File tree

2 files changed

+90
-28
lines changed

2 files changed

+90
-28
lines changed

lib/workos/sso.rb

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ def profile_and_token(code:, client_id: nil)
120120
code: code,
121121
}
122122

123-
response = client.request(post_request(path: '/sso/token', body: body))
124-
check_and_raise_profile_and_token_error(response: response)
123+
response = execute_request(
124+
request: post_request(path: '/sso/token', body: body),
125+
)
125126

126127
WorkOS::ProfileAndToken.new(response.body)
127128
end
@@ -229,28 +230,6 @@ def validate_authorization_url_arguments(
229230
raise ArgumentError, "#{provider} is not a valid value." \
230231
" `provider` must be in #{PROVIDERS}"
231232
end
232-
233-
def check_and_raise_profile_and_token_error(response:)
234-
begin
235-
body = JSON.parse(response.body)
236-
return if body['access_token'] && body['profile']
237-
238-
message = body['message']
239-
error = body['error']
240-
error_description = body['error_description']
241-
request_id = response['x-request-id']
242-
rescue StandardError
243-
message = 'Something went wrong'
244-
end
245-
246-
raise APIError.new(
247-
message: message,
248-
error: error,
249-
error_description: error_description,
250-
http_status: nil,
251-
request_id: request_id,
252-
)
253-
end
254233
end
255234
end
256235
end

spec/lib/workos/sso_spec.rb

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,10 +416,73 @@
416416
expect do
417417
described_class.profile_and_token(**args)
418418
end.to raise_error(
419-
WorkOS::APIError,
420-
'error: some error, error_description: some error description - request ID: request-id',
419+
WorkOS::UnprocessableEntityError,
420+
'Status 422, some error - request ID: request-id',
421421
)
422422
end
423+
424+
it 'raises an exception with proper error object attributes' do
425+
expect do
426+
described_class.profile_and_token(**args)
427+
end.to raise_error(WorkOS::UnprocessableEntityError)
428+
end
429+
430+
it 'includes proper error attributes' do
431+
error = begin
432+
described_class.profile_and_token(**args)
433+
rescue WorkOS::UnprocessableEntityError => e
434+
e
435+
end
436+
437+
expect(error.http_status).to eq(422)
438+
expect(error.request_id).to eq('request-id')
439+
expect(error.error).to eq('some error')
440+
expect(error.message).to include('some error')
441+
end
442+
end
443+
444+
context 'with detailed field validation errors' do
445+
before do
446+
stub_request(:post, 'https://api.workos.com/sso/token').
447+
with(headers: headers, body: request_body).
448+
to_return(
449+
headers: { 'X-Request-ID' => 'request-id' },
450+
status: 422,
451+
body: {
452+
"message": 'Validation failed',
453+
"code": 'invalid_request_parameters',
454+
"errors": [
455+
{
456+
"field": 'code',
457+
"code": 'missing_required_parameter',
458+
"message": 'The code parameter is required',
459+
}
460+
],
461+
}.to_json,
462+
)
463+
end
464+
465+
it 'raises an exception with detailed field errors' do
466+
expect do
467+
described_class.profile_and_token(**args)
468+
end.to raise_error(WorkOS::UnprocessableEntityError)
469+
end
470+
471+
it 'includes detailed field error attributes' do
472+
error = begin
473+
described_class.profile_and_token(**args)
474+
rescue WorkOS::UnprocessableEntityError => e
475+
e
476+
end
477+
478+
expect(error.http_status).to eq(422)
479+
expect(error.request_id).to eq('request-id')
480+
expect(error.code).to eq('invalid_request_parameters')
481+
expect(error.errors).not_to be_nil
482+
expect(error.errors).to include('code: missing_required_parameter')
483+
expect(error.message).to include('Validation failed')
484+
expect(error.message).to include('(code: missing_required_parameter)')
485+
end
423486
end
424487

425488
context 'with an expired code' do
@@ -440,11 +503,31 @@
440503
expect do
441504
described_class.profile_and_token(**args)
442505
end.to raise_error(
443-
WorkOS::APIError,
444-
"error: invalid_grant, error_description: The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
506+
WorkOS::InvalidRequestError,
507+
"Status 400, error: invalid_grant, error_description: The code '01DVX3C5Z367SFHR8QNDMK7V24'" \
445508
' has expired or is invalid. - request ID: request-id',
446509
)
447510
end
511+
512+
it 'raises an exception with proper error object attributes' do
513+
expect do
514+
described_class.profile_and_token(**args)
515+
end.to raise_error(WorkOS::InvalidRequestError)
516+
end
517+
518+
it 'includes proper error attributes' do
519+
error = begin
520+
described_class.profile_and_token(**args)
521+
rescue WorkOS::InvalidRequestError => e
522+
e
523+
end
524+
525+
expect(error.http_status).to eq(400)
526+
expect(error.request_id).to eq('request-id')
527+
expect(error.error).to eq('invalid_grant')
528+
expect(error.error_description).to eq("The code '01DVX3C5Z367SFHR8QNDMK7V24' has expired or is invalid.")
529+
expect(error.message).to include('invalid_grant')
530+
end
448531
end
449532
end
450533

0 commit comments

Comments
 (0)