Skip to content

Commit e323c83

Browse files
committed
generic: add OAuth refresh token support
Add support for storing and using OAuth refresh tokens. Prepend "refresh_token" as a subdomain to give better chances of avoiding a name clash compared with appending "/refresh_token" to the path component.
1 parent 720a078 commit e323c83

File tree

1 file changed

+33
-0
lines changed

1 file changed

+33
-0
lines changed

src/shared/Core/GenericHostProvider.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,33 @@ private async Task<ICredential> GetOAuthAccessToken(Uri remoteUri, string userNa
128128
Context.Trace,
129129
config.UseAuthHeader);
130130

131+
//
132+
// Prepend "refresh_token" to the hostname to get a (hopefully) unique service name that
133+
// doesn't clash with an existing credential service.
134+
//
135+
// Appending "/refresh_token" to the end of the remote URI may not always result in a unique
136+
// service because users may set credential.useHttpPath and include "/refresh_token" as a
137+
// path name.
138+
//
139+
string refreshService = new UriBuilder(remoteUri) { Host = $"refresh_token.{remoteUri.Host}" }
140+
.Uri.AbsoluteUri.TrimEnd('/');
141+
142+
// Try to use a refresh token if we have one
143+
ICredential refreshToken = Context.CredentialStore.Get(refreshService, userName);
144+
if (refreshToken != null)
145+
{
146+
var refreshResult = await client.GetTokenByRefreshTokenAsync(refreshToken.Password, CancellationToken.None);
147+
148+
// Store new refresh token if we have been given one
149+
if (!string.IsNullOrWhiteSpace(refreshResult.RefreshToken))
150+
{
151+
Context.CredentialStore.AddOrUpdate(refreshService, refreshToken.Account, refreshToken.Password);
152+
}
153+
154+
// Return the new access token
155+
return new GitCredential(oauthUser,refreshResult.AccessToken);
156+
}
157+
131158
// Determine which interactive OAuth mode to use. Start by checking for mode preference in config
132159
var supportedModes = OAuthAuthenticationModes.All;
133160
if (Context.Settings.TryGetSetting(
@@ -170,6 +197,12 @@ private async Task<ICredential> GetOAuthAccessToken(Uri remoteUri, string userNa
170197
throw new Exception("No authentication mode selected!");
171198
}
172199

200+
// Store the refresh token if we have one
201+
if (!string.IsNullOrWhiteSpace(tokenResult.RefreshToken))
202+
{
203+
Context.CredentialStore.AddOrUpdate(refreshService, oauthUser, tokenResult.RefreshToken);
204+
}
205+
173206
return new GitCredential(oauthUser, tokenResult.AccessToken);
174207
}
175208

0 commit comments

Comments
 (0)