-
Notifications
You must be signed in to change notification settings - Fork 1k
feat: ensure OAuth2 refresh tokens outlive access tokens #19769
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -292,6 +292,57 @@ func must[T any](value T, err error) T { | |
return value | ||
} | ||
|
||
func TestDeploymentValues_Validate_RefreshLifetime(t *testing.T) { | ||
t.Parallel() | ||
|
||
mk := func(access, refresh time.Duration) *codersdk.DeploymentValues { | ||
dv := &codersdk.DeploymentValues{} | ||
dv.Sessions.DefaultDuration = serpent.Duration(access) | ||
dv.Sessions.RefreshDefaultDuration = serpent.Duration(refresh) | ||
return dv | ||
} | ||
|
||
t.Run("EqualDurations_Error", func(t *testing.T) { | ||
t.Parallel() | ||
dv := mk(1*time.Hour, 1*time.Hour) | ||
err := dv.Validate() | ||
require.Error(t, err) | ||
require.ErrorContains(t, err, "must be strictly greater") | ||
}) | ||
|
||
t.Run("RefreshShorter_Error", func(t *testing.T) { | ||
t.Parallel() | ||
dv := mk(2*time.Hour, 1*time.Hour) | ||
err := dv.Validate() | ||
require.Error(t, err) | ||
require.ErrorContains(t, err, "must be strictly greater") | ||
}) | ||
|
||
t.Run("RefreshZero_Error", func(t *testing.T) { | ||
t.Parallel() | ||
dv := mk(1*time.Hour, 0) | ||
err := dv.Validate() | ||
require.Error(t, err) | ||
require.ErrorContains(t, err, "must be strictly greater") | ||
}) | ||
|
||
t.Run("AccessUninitialized_Error", func(t *testing.T) { | ||
t.Parallel() | ||
// Access duration is zero (uninitialized); refresh is valid. | ||
dv := mk(0, 48*time.Hour) | ||
err := dv.Validate() | ||
require.Error(t, err) | ||
require.ErrorContains(t, err, "developer error: sessions configuration appears uninitialized") | ||
}) | ||
|
||
t.Run("RefreshLonger_OK", func(t *testing.T) { | ||
t.Parallel() | ||
dv := mk(1*time.Hour, 48*time.Hour) | ||
err := dv.Validate() | ||
require.NoError(t, err) | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't forget to also add a test to hit the code path you added to check for uninitialized default duration |
||
} | ||
|
||
func TestDeploymentValues_DurationFormatNanoseconds(t *testing.T) { | ||
t.Parallel() | ||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what case would it make sense to set the default refresh duration to be the same as the access token lifetime? In that case you may as well just disable refresh tokens entirely. If we allow setting this equal to or very close to access token lifetime, I foresee customers running into issues. Would it make sense to validate that
RefreshDefaultDuration
is strictly greater than access token lifetime, and raise an error if this is not the case?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that makes sense. I've added a validation to catch those cases.
It errors out if the constraint of refresh token lifetime < access token lifetime, since debugging why refresh tokens aren't issued would become even harder if we fail silently.