Skip to content

Commit

Permalink
Refresh token and retry on authorization errors
Browse files Browse the repository at this point in the history
Apple seems to be revoking tokens before their expiration dates. Several
users reporting problems on issue [#19072][1] were likely affected by
it. Sometimes changing the token duration will work around the problem,
as the tokens are likely being revoked later in the future and allowing
the wait to complete.

This can be seen in practice by adding a `@token.refresh!` couple of extra log
messages to [api_client.rb][2] right at the point where we get an
`UnauthorizedAccessError`:

```
INFO  [2021-10-19 18:38:31.74]: Successfully uploaded the new binary to App Store Connect
INFO  [2021-10-19 18:38:31.74]: If you want to skip waiting for the processing to be finished, use the `skip_waiting_for_build_processing` option
INFO  [2021-10-19 18:38:31.74]: Note that if `skip_waiting_for_build_processing` is used but a `changelog` is supplied, this process will wait for the build to appear on AppStoreConnect, update the changelog and then skip the remaining of the processing steps.
DEBUG [2021-10-19 18:38:31.82]: App Platform (ios)
INFO  [2021-10-19 18:38:31.92]: Waiting for processing on... app_id: 1370986669, app_version: 2.23.2, build_version: 262025, platform: IOS
WARN  [2021-10-19 18:38:32.26]: Read more information on why this build isn't showing up yet - #14997
INFO  [2021-10-19 18:38:32.26]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:39:02.70]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)

token expired?: false  - expiration: 2021-10-19 18:45:04 -0400
Token has expired, has been revoked, or is invalid! Trying to refresh

INFO  [2021-10-19 18:39:33.26]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:40:03.69]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:40:34.33]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:41:04.76]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:41:35.21]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:42:05.67]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)

token expired?: false  - expiration: 2021-10-19 18:47:52 -0400
Token has expired, has been revoked, or is invalid! Trying to refresh

INFO  [2021-10-19 18:42:36.34]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:43:06.80]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
INFO  [2021-10-19 18:43:37.23]: Waiting for the build to show up in the build list - this may take a few minutes (check your email for processing issues if this continues)
```

The logs above show that, even though the current token is not expired, the
appconnect API responds with a 401 and the process would otherwise fail.

This ignores the `UnauthorizedAccessError` exception and instead refreshes the
token right before raising a `RetryError`.

[1]: #19072
[2]: https://github.com/fastlane/fastlane/blob/62af236780a9eace9d0487d0767f50d1a17a1c6c/spaceship/lib/spaceship/connect_api/api_client.rb#L172-L175
  • Loading branch information
andersonvom committed Oct 20, 2021
1 parent 27a41b8 commit b140042
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 40 deletions.
17 changes: 8 additions & 9 deletions spaceship/lib/spaceship/connect_api/api_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ def delete(url_or_path, params = nil, body = nil)

protected

class TimeoutRetryError < StandardError
class RetryError < StandardError
def initialize(msg)
super
end
Expand All @@ -165,15 +165,16 @@ def with_asc_retry(tries = 5, &_block)

if [500, 504].include?(status)
msg = "Timeout received! Retrying after 3 seconds (remaining: #{tries})..."
raise TimeoutRetryError, msg
raise RetryError, msg
elsif status == 401
msg = "Token has expired, or has been revoked! Trying to refresh..."
puts(msg) if Spaceship::Globals.verbose?
@token.refresh!
raise RetryError, "Retrying after 3 seconds (remaining: #{tries})..."
end

return response
rescue UnauthorizedAccessError => error
# Catch unathorized access and re-raising
# There is no need to try again
raise error
rescue TimeoutRetryError => error
rescue RetryError => error
tries -= 1
puts(error) if Spaceship::Globals.verbose?
if tries.zero?
Expand Down Expand Up @@ -217,8 +218,6 @@ def handle_error(response)
end

case response.status.to_i
when 401
raise UnauthorizedAccessError, format_errors(response)
when 403
error = (body['errors'] || []).first || {}
error_code = error['code']
Expand Down
31 changes: 0 additions & 31 deletions spaceship/spec/connect_api/api_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,6 @@ def stub_client_request(uri, status, body)
client.get('')
end

it 'raise on 401' do
body = JSON.generate({ "errors": [] })
stub_client_request(client.hostname, 401, body)

expect do
client.get('')
end.to raise_error(Spaceship::UnauthorizedAccessError)
end

it 'raise on 403 with program license agreement updated' do
body = JSON.generate({ "errors": [{ "code": "FORBIDDEN.REQUIRED_AGREEMENTS_MISSING_OR_EXPIRED" }] })
stub_client_request(client.hostname, 403, body)
Expand Down Expand Up @@ -145,28 +136,6 @@ def stub_client_request(uri, status, body)
end
end

describe "status of 401" do
before(:each) do
allow(mock_response).to receive(:status).and_return(401)
end

it 'raises UnauthorizedAccessError with no errors in body' do
allow(mock_response).to receive(:body).and_return({})

expect do
client.send(:handle_error, mock_response)
end.to raise_error(Spaceship::UnauthorizedAccessError, /Unknown error/)
end

it 'raises UnauthorizedAccessError when body is string' do
allow(mock_response).to receive(:body).and_return('{"errors":[{"title": "Some title", "detail": "some detail"}]}')

expect do
client.send(:handle_error, mock_response)
end.to raise_error(Spaceship::UnauthorizedAccessError, /Some title - some detail/)
end
end

describe "status of 403" do
before(:each) do
allow(mock_response).to receive(:status).and_return(403)
Expand Down

0 comments on commit b140042

Please sign in to comment.