Skip to content

fix: Tune auth token refresh and valid windows. #2630

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

Merged
merged 4 commits into from
Dec 12, 2023
Merged

Conversation

amanda-tarafa
Copy link
Contributor

And some code cleanup and refactor.

@jskeet as always, one commit at a time.

@amanda-tarafa amanda-tarafa requested a review from jskeet December 7, 2023 05:18
@amanda-tarafa amanda-tarafa requested a review from a team as a code owner December 7, 2023 05:18
Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this is absolutely fine - just a few questions that affect the public API. Probably worth chatting about in a meeting rather than back-and-forth here.

// it's expired now.
long isHardExpiredSeconds = 60 * 15;
// it's not valid and may not be used.
long mayNotBeUsesSeconds = 60 * 15;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uses => Used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


/// <summary>
/// Returns true if the token represented by this token response is valid, that is, it may be used
/// for authentication and authorizations purposes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authorizations => authorization

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

/// <list type="bullet">
/// <item>At least one of <see cref="AccessToken"/> and <see cref="IdToken"/> is not null.</item>
/// <item><see cref="ExpiresInSeconds"/> is not null.</item>
/// <item>The token has not expired and will not expire in the very near future. That is if
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. This is where I have a problem with "valid" as the term. If a token hasn't expired, I would say it's valid. If I send it to a service and there isn't clock skew involved, it's still going to succeed.

Do we need to make this public immediately? Can we make it internal for now (or even remove it if we're using a clock elsewhere) and then make it public when we've got a better name?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm removing this property entirely, we don't use it and we didn't have anything like this before.

internal bool MayBeUsed(IClock clock) =>
(AccessToken is not null || IdToken is not null) &&
ExpiresInSeconds.HasValue &&
IssuedUtc.AddSeconds(ExpiresInSeconds.Value - TokenInvalidWindowSeconds) > clock.UtcNow;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a potential future refactor, I wonder whether we should have an EffectiveExpiryTimeUtc which is IssuedUtc.AddSeconds(ExpiresInSeconds.Value - TokenInvalidWindowSeconds) (and make it nullable) so we could make this:

(AccessToken is not null || IdToken is not null) &&
EffectiveExpiryUtc is DateTime effectiveExpiry &&
clock.UtcNow < effectiveExpiry

Happy to bikeshed the "effective expiry" name - maybe "DoNotUseAfter" or something :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, and I'm doing the same for the ShouldRefresh one. I'm adding: RefreshWindowStartUtc and ExpiryWindowStartUtc. Does that sound good?

@@ -135,7 +135,7 @@ public bool ShouldRequestAuthorizationCode(TokenResponse token)
// If the flow includes a parameter that requires a new token, if the stored token is null or it doesn't
// have a refresh token and the access token is expired we need to retrieve a new authorization code.
return Flow.ShouldForceTokenRetrieval() || token == null || (token.RefreshToken == null
&& token.IsExpired(flow.Clock));
&& token.ShouldBeRefreshed(flow.Clock));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a semantic change, right? (Admittedly one that would only be hit very rarely.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've talked about this offline, but just to close the loop: this is just change in the method name that was not clear before. The semantics are exactly the same as before, it's just the new method name that matches those semantics better.

Copy link
Contributor Author

@amanda-tarafa amanda-tarafa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jskeet I've addressed your comments and also increased the "invalid" window to 1 minute before expiry (from 30 seconds). Changes are in ordered commits named "Address comments..."

// it's expired now.
long isHardExpiredSeconds = 60 * 15;
// it's not valid and may not be used.
long mayNotBeUsesSeconds = 60 * 15;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


/// <summary>
/// Returns true if the token represented by this token response is valid, that is, it may be used
/// for authentication and authorizations purposes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

/// <list type="bullet">
/// <item>At least one of <see cref="AccessToken"/> and <see cref="IdToken"/> is not null.</item>
/// <item><see cref="ExpiresInSeconds"/> is not null.</item>
/// <item>The token has not expired and will not expire in the very near future. That is if
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm removing this property entirely, we don't use it and we didn't have anything like this before.

@@ -135,7 +135,7 @@ public bool ShouldRequestAuthorizationCode(TokenResponse token)
// If the flow includes a parameter that requires a new token, if the stored token is null or it doesn't
// have a refresh token and the access token is expired we need to retrieve a new authorization code.
return Flow.ShouldForceTokenRetrieval() || token == null || (token.RefreshToken == null
&& token.IsExpired(flow.Clock));
&& token.ShouldBeRefreshed(flow.Clock));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've talked about this offline, but just to close the loop: this is just change in the method name that was not clear before. The semantics are exactly the same as before, it's just the new method name that matches those semantics better.

internal bool MayBeUsed(IClock clock) =>
(AccessToken is not null || IdToken is not null) &&
ExpiresInSeconds.HasValue &&
IssuedUtc.AddSeconds(ExpiresInSeconds.Value - TokenInvalidWindowSeconds) > clock.UtcNow;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, and I'm doing the same for the ShouldRefresh one. I'm adding: RefreshWindowStartUtc and ExpiryWindowStartUtc. Does that sound good?

Copy link
Collaborator

@jskeet jskeet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks!

This is to account for Metadata Servers caching the tokens.
We are using a shared extension method instead.
@amanda-tarafa
Copy link
Contributor Author

Thanks! I've squashed the review commits and will merge on green.

@amanda-tarafa amanda-tarafa merged commit 01f70c7 into main Dec 12, 2023
@amanda-tarafa amanda-tarafa deleted the refresh_window branch December 12, 2023 17:13
amanda-tarafa added a commit that referenced this pull request Jan 9, 2024
Fixes:

- #2613 Default JSON serializer is not affected by gloabl JSON settings.
- #2630 Tune authorization token staleness and validity windows so that it doesn't overlap with Metadata Server authorization token caching.

Features:

- #2616 Makes batch response handling more efficient, particularly benefiting large responses.
amanda-tarafa added a commit that referenced this pull request Jan 9, 2024
Fixes:

- #2613 Default JSON serializer is not affected by gloabl JSON settings.
- #2630 Tune authorization token staleness and validity windows so that it doesn't overlap with Metadata Server authorization token caching.

Features:

- #2616 Makes batch response handling more efficient, particularly benefiting large responses.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants