This question isn't duplicate AT ALL. I hope this help others not spending days like I have spent.
After almost 4 days I have found out how to get a fresh access token in the google api using OWIN.
I'm going to post the solution, but first, I MUST say that what helped me to start getting a clue about my error was setting up the Debug Symbols for the Katana project. See this link:
http://www.symbolsource.org/Public/Home/VisualStudio
This image show how to configure Debug Symbols Servers.
And this one shows the Katana Debug Symbols being loaded.
After that, I found out that my problem was that Google API was returning 403: Forbidden
"Access Not Configured. Please use Google Developers Console to activate the API for your project"
Then, found on stack overflow this post:
"Access Not Configured. Please use Google Developers Console to activate the API for your project."
more specifically this Answer: https://stackoverflow.com/a/24401189/833846
After that, I went to Google Developers Console and setup up Google+ API
And then, voillá! It worked.
Now, the code to get a fresh access token using the refresh token (I haven't found any way to accomplish that using the OWIN API).
public static class TokenValidator
{
/// <summary>
/// Obtém um novo access token na API do google.
/// </summary>
/// <param name="clientId"></param>
/// <param name="clientSecret"></param>
/// <param name="refreshToken"></param>
/// <returns></returns>
public static GoogleRefreshTokenModel ValidateGoogleToken(string clientId, string clientSecret, string refreshToken)
{
const string url = "https://accounts.google.com/o/oauth2/token";
var parameters = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("client_id", clientId),
new KeyValuePair<string, string>("client_secret", clientSecret),
new KeyValuePair<string, string>("grant_type", "refresh_token"),
new KeyValuePair<string, string>("refresh_token", refreshToken)
};
var content = GetContentAsync(url, "POST", parameters);
var token = JsonConvert.DeserializeObject<GoogleRefreshTokenModel>(content);
return token;
}
private static string GetContentAsync(string url,
string method = "POST",
IEnumerable<KeyValuePair<string, string>> parameters = null)
{
return method == "POST" ? PostAsync(url, parameters) : GetAsync(url, parameters);
}
private static string PostAsync(string url, IEnumerable<KeyValuePair<string, string>> parameters = null)
{
var uri = new Uri(url);
var request = WebRequest.Create(uri) as HttpWebRequest;
request.Method = "POST";
request.KeepAlive = true;
request.ContentType = "application/x-www-form-urlencoded";
var postParameters = GetPostParameters(parameters);
var bs = Encoding.UTF8.GetBytes(postParameters);
using (var reqStream = request.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
}
using (var response = request.GetResponse())
{
var sr = new StreamReader(response.GetResponseStream());
var jsonResponse = sr.ReadToEnd();
sr.Close();
return jsonResponse;
}
}
private static string GetPostParameters(IEnumerable<KeyValuePair<string, string>> parameters = null)
{
var postParameters = string.Empty;
foreach (var parameter in parameters)
{
postParameters += string.Format("&{0}={1}", parameter.Key,
HttpUtility.HtmlEncode(parameter.Value));
}
postParameters = postParameters.Substring(1);
return postParameters;
}
private static string GetAsync(string url, IEnumerable<KeyValuePair<string, string>> parameters = null)
{
url += "?" + GetQueryStringParameters(parameters);
var forIdsWebRequest = WebRequest.Create(url);
using (var response = (HttpWebResponse)forIdsWebRequest.GetResponse())
{
using (var data = response.GetResponseStream())
using (var reader = new StreamReader(data))
{
var jsonResponse = reader.ReadToEnd();
return jsonResponse;
}
}
}
private static string GetQueryStringParameters(IEnumerable<KeyValuePair<string, string>> parameters = null)
{
var queryStringParameters = string.Empty;
foreach (var parameter in parameters)
{
queryStringParameters += string.Format("&{0}={1}", parameter.Key,
HttpUtility.HtmlEncode(parameter.Value));
}
queryStringParameters = queryStringParameters.Substring(1);
return queryStringParameters;
}
}
IMPORTANT 1: To get a refresh token you must set the "access_type" to "offline" in the "ExecuteResult" method, this way:
properties.Dictionary["access_type"] = "offline";
IMPORTANT 2: Once you get your refresh token, you must store it and in some secure source. Google API won't issue you a new refresh token, unless you set "approval_prompt" to "force" before you call the line (in the same method):
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, LoginProvider);
I also recommend taking a look at:
Google API Offline Access
Google OAUTH 2.0 Playground
Google API Discovery Check