I'm having issues with setting up google api oauth2 to access the calendar api. I have used the following code below, this works fine and prompts the user to grant access to the calendar api. However once the user has allowed access the site ends up in a redirect loop, when debugging it appears that result.Credentials is always null. Using fiddler I can see that a token is being received from the following url: accounts.google.com/o/oauth2/token
with the following response:
{
"access_token" : "TOKEN",
"token_type" : "Bearer",
"expires_in" : 3600
}
I'm completely stumped as to why the credentials are never populated. Here's the code I'm using:
public class AppFlowMetadata : FlowMetadata
{
private static readonly IAuthorizationCodeFlow flow =
new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "CLIENT_ID",
ClientSecret = "CLIENT_SECRET"
},
Scopes = new[] { CalendarService.Scope.Calendar }
});
public override string GetUserId(Controller controller)
{
// In this sample we use the session to store the user identifiers.
// That's not the best practice, because you should have a logic to identify
// a user. You might want to use "OpenID Connect".
// You can read more about the protocol in the following link:
// https://developers.google.com/accounts/docs/OAuth2Login.
var user = controller.Session["user"];
if (user == null)
{
user = Guid.NewGuid();
controller.Session["user"] = user;
}
return user.ToString();
}
public override IAuthorizationCodeFlow Flow
{
get { return flow; }
}
}
public class AuthCallbackController : Google.Apis.Auth.OAuth2.Mvc.Controllers.AuthCallbackController
{
protected override Google.Apis.Auth.OAuth2.Mvc.FlowMetadata FlowData
{
get { return new AppFlowMetadata(); }
}
}
public class GoogleController : Controller
{
// GET: Google
[Route("google")]
public ActionResult Index(CancellationToken cancellationToken)
{
//try to get results
var result = new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).
AuthorizeAsync(cancellationToken).Result;
if (result.Credential != null)
{
//// This bit checks if the token is out of date,
//// and refreshes the access token using the refresh token.
if (result.Credential.Token.IsExpired(SystemClock.Default))
{
Google.Apis.Auth.OAuth2.Responses.TokenResponse token = new Google.Apis.Auth.OAuth2.Responses.TokenResponse();
//If the token is expired recreate the token
token = result.Credential.Flow.RefreshTokenAsync("1", result.Credential.Token.RefreshToken, CancellationToken.None).Result;
//Get the authorization details back
result = new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken).Result;
}
var service = new CalendarService(new BaseClientService.Initializer
{
HttpClientInitializer = result.Credential,
ApplicationName = "ASP.NET MVC Sample"
});
return View();
}
else
{
return new RedirectResult(result.RedirectUri);
}
}