aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Jan Tattermusch <jtattermusch@google.com>2015-04-27 15:12:36 -0700
committerGravatar Jan Tattermusch <jtattermusch@google.com>2015-04-27 15:12:36 -0700
commitb4ef7c9f37bae90ec8c0e2bdcce5ed505601c7e2 (patch)
treec1522785bb3a3fdeca2cec96ae6e5d2a3c8cf385 /src
parent1ca56b9d8ad02b0fa426986142cbaf01c455bd0a (diff)
logic for refreshing access token
Diffstat (limited to 'src')
-rw-r--r--src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs53
1 files changed, 48 insertions, 5 deletions
diff --git a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
index ae4a987dcb..ca384d1a6e 100644
--- a/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
+++ b/src/csharp/Grpc.Auth/OAuth2InterceptorFactory.cs
@@ -41,6 +41,7 @@ using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
+using Google.Apis.Util;
using Grpc.Core;
using Grpc.Core.Utils;
@@ -48,14 +49,56 @@ namespace Grpc.Auth
{
public static class OAuth2InterceptorFactory
{
+ /// <summary>
+ /// Creates OAuth2 interceptor.
+ /// </summary>
public static HeaderInterceptorDelegate Create(GoogleCredential googleCredential)
{
- ServiceCredential credential = googleCredential.InternalCredential;
- credential.RequestAccessTokenAsync(CancellationToken.None).Wait();
- string accessToken = credential.Token.AccessToken;
+ var interceptor = new OAuth2Interceptor(googleCredential.InternalCredential, SystemClock.Default);
+ return new HeaderInterceptorDelegate(interceptor.InterceptHeaders);
+ }
+
+ /// <summary>
+ /// Injects OAuth2 authorization header into initial metadata (= request headers).
+ /// </summary>
+ private class OAuth2Interceptor
+ {
+ private const string AuthorizationHeader = "Authorization";
+ private const string Schema = "Bearer";
+
+ private ServiceCredential credential;
+ private IClock clock;
+
+ public OAuth2Interceptor(ServiceCredential credential, IClock clock)
+ {
+ this.credential = credential;
+ this.clock = clock;
+ }
+
+ /// <summary>
+ /// Gets access token and requests refreshing it if is going to expire soon.
+ /// </summary>
+ /// <param name="cancellationToken"></param>
+ /// <returns></returns>
+ public string GetAccessToken(CancellationToken cancellationToken)
+ {
+ if (credential.Token == null || credential.Token.IsExpired(clock))
+ {
+ // TODO(jtattermusch): Parallel requests will spawn multiple requests to refresh the token once the token expires.
+ // TODO(jtattermusch): Rethink synchronous wait to obtain the result.
+ if (!credential.RequestAccessTokenAsync(cancellationToken).Result)
+ {
+ throw new InvalidOperationException("The access token has expired but we can't refresh it");
+ }
+ }
+ return credential.Token.AccessToken;
+ }
- // TODO(jtattermusch): implement token refresh logic!!
- return new HeaderInterceptorDelegate((b) => { b.Add(new Metadata.MetadataEntry("Authorization", "Bearer " + accessToken)); });
+ public void InterceptHeaders(Metadata.Builder headerBuilder)
+ {
+ var accessToken = GetAccessToken(CancellationToken.None);
+ headerBuilder.Add(new Metadata.MetadataEntry(AuthorizationHeader, Schema + " " + accessToken));
+ }
}
}
}