From 4fc74a445f929d7f270be250c399647dff4558b6 Mon Sep 17 00:00:00 2001 From: Chris Roos Date: Thu, 17 Jul 2025 09:29:10 +0100 Subject: [PATCH 1/2] Refresh access tokens before expiry We've seen a small number of exceptions in Experience CS[1] which are caused by a 401 response from Editor API. I'm fairly confident these are occurring when the access token used to make the request to Editor API has expired. My hypothesis is that the token is valid at the time the request comes into Experience CS (and therefore the auto refresh behaviour isn't triggered) but is invalid by the time we make the request to Editor API. This change reduces the risk of this happening by refreshing the token if it expires in the next 60 seconds. [1]: https://github.com/RaspberryPiFoundation/experience-cs/issues/914 --- lib/rpi_auth/controllers/auto_refreshing_token.rb | 4 +++- spec/dummy/spec/requests/refresh_credentials_spec.rb | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/rpi_auth/controllers/auto_refreshing_token.rb b/lib/rpi_auth/controllers/auto_refreshing_token.rb index 698b1fa..2a9f558 100644 --- a/lib/rpi_auth/controllers/auto_refreshing_token.rb +++ b/lib/rpi_auth/controllers/auto_refreshing_token.rb @@ -5,6 +5,8 @@ module RpiAuth module Controllers module AutoRefreshingToken + REFRESH_WINDOW_IN_SECONDS = 60 + extend ActiveSupport::Concern include CurrentUser @@ -18,7 +20,7 @@ module AutoRefreshingToken def refresh_credentials_if_needed return unless current_user - return if Time.now.to_i < current_user.expires_at + return if Time.now.to_i + REFRESH_WINDOW_IN_SECONDS <= current_user.expires_at current_user.refresh_credentials! self.current_user = current_user diff --git a/spec/dummy/spec/requests/refresh_credentials_spec.rb b/spec/dummy/spec/requests/refresh_credentials_spec.rb index 7c7ca82..a2a5300 100644 --- a/spec/dummy/spec/requests/refresh_credentials_spec.rb +++ b/spec/dummy/spec/requests/refresh_credentials_spec.rb @@ -63,15 +63,15 @@ log_in(user:) end - context 'when the access token has not expired' do - let(:expires_at) { 10.seconds.from_now } + context 'when the access token is valid for at least another 60 seconds' do + let(:expires_at) { 60.seconds.from_now } it_behaves_like 'the user is logged in' it_behaves_like 'there is no attempt to renew the token' end - context 'when the access token has expired' do - let(:expires_at) { 10.seconds.ago } + context 'when the access token expires in the next 60 seconds' do + let(:expires_at) { 59.seconds.from_now } before do allow(stub_oauth_client).to receive(:refresh_credentials).with(any_args).and_return({ access_token: 'foo', From 10350f7cc55a544f43a77523d73a268368e906d9 Mon Sep 17 00:00:00 2001 From: Chris Roos Date: Thu, 17 Jul 2025 12:19:14 +0100 Subject: [PATCH 2/2] Bump version to 4.2.1 and prepare for release I've gone with a patch version bump because I think the changed behaviour is closer to a bug fix than it is to backward-compatible additional functionality (minor version bump) or to a backward-incompatible change (major version bump). NOTE. I've manually bumped the version in the individual gemfile.lock files because running `bundle update --conservative rpi_auth` resulted in updates to a number of other unrelated Gems and I didn't want to have to consider those in this PR. --- CHANGELOG.md | 9 ++++++++- gemfiles/rails_6.1.gemfile.lock | 2 +- gemfiles/rails_7.0.gemfile.lock | 2 +- gemfiles/rails_7.1.gemfile.lock | 2 +- gemfiles/rails_7.2.gemfile.lock | 2 +- lib/rpi_auth/version.rb | 2 +- 6 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1042755..19128c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +## [v4.2.1] + +### Fixed + +- Refresh access tokens before expiry (#89) + ## [v4.2.0] ### Added @@ -154,7 +160,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - rails model concern to allow host app to add auth behaviour to a model - callback, logout and failure routes to handle auth -[Unreleased]: https://github.com/RaspberryPiFoundation/rpi-auth/compare/v4.2.0...HEAD +[Unreleased]: https://github.com/RaspberryPiFoundation/rpi-auth/compare/v4.2.1...HEAD +[v4.2.1]: https://github.com/RaspberryPiFoundation/rpi-auth/releases/tag/v4.2.1 [v4.2.0]: https://github.com/RaspberryPiFoundation/rpi-auth/releases/tag/v4.2.0 [v4.1.1]: https://github.com/RaspberryPiFoundation/rpi-auth/releases/tag/v4.1.1 [v4.1.0]: https://github.com/RaspberryPiFoundation/rpi-auth/releases/tag/v4.1.0 diff --git a/gemfiles/rails_6.1.gemfile.lock b/gemfiles/rails_6.1.gemfile.lock index f85ac1b..91e5f35 100644 --- a/gemfiles/rails_6.1.gemfile.lock +++ b/gemfiles/rails_6.1.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - rpi_auth (4.2.0) + rpi_auth (4.2.1) oauth2 omniauth-rails_csrf_protection (~> 1.0.0) omniauth_openid_connect (~> 0.7.1) diff --git a/gemfiles/rails_7.0.gemfile.lock b/gemfiles/rails_7.0.gemfile.lock index b359f3c..cde00da 100644 --- a/gemfiles/rails_7.0.gemfile.lock +++ b/gemfiles/rails_7.0.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - rpi_auth (4.2.0) + rpi_auth (4.2.1) oauth2 omniauth-rails_csrf_protection (~> 1.0.0) omniauth_openid_connect (~> 0.7.1) diff --git a/gemfiles/rails_7.1.gemfile.lock b/gemfiles/rails_7.1.gemfile.lock index 39b0d2f..6affe4e 100644 --- a/gemfiles/rails_7.1.gemfile.lock +++ b/gemfiles/rails_7.1.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - rpi_auth (4.2.0) + rpi_auth (4.2.1) oauth2 omniauth-rails_csrf_protection (~> 1.0.0) omniauth_openid_connect (~> 0.7.1) diff --git a/gemfiles/rails_7.2.gemfile.lock b/gemfiles/rails_7.2.gemfile.lock index da3b245..db2646c 100644 --- a/gemfiles/rails_7.2.gemfile.lock +++ b/gemfiles/rails_7.2.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - rpi_auth (4.2.0) + rpi_auth (4.2.1) oauth2 omniauth-rails_csrf_protection (~> 1.0.0) omniauth_openid_connect (~> 0.7.1) diff --git a/lib/rpi_auth/version.rb b/lib/rpi_auth/version.rb index b501690..bcfaacf 100644 --- a/lib/rpi_auth/version.rb +++ b/lib/rpi_auth/version.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true module RpiAuth - VERSION = '4.2.0' + VERSION = '4.2.1' end