/*
Copyright 2013 Google Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
using System;
using Google.Apis.Util;
using System.Threading.Tasks;
using System.Net.Http;
using Google.Apis.Json;
using Google.Apis.Logging;
namespace Google.Apis.Auth.OAuth2.Responses
{
///
/// OAuth 2.0 model for a successful access token response as specified in
/// http://tools.ietf.org/html/rfc6749#section-5.1.
///
public class TokenResponse
{
private const int TokenExpiryTimeWindowSeconds = 60 * 5; // Refresh token 5 minutes before it expires.
/// Gets or sets the access token issued by the authorization server.
[Newtonsoft.Json.JsonPropertyAttribute("access_token")]
public string AccessToken { get; set; }
///
/// Gets or sets the token type as specified in http://tools.ietf.org/html/rfc6749#section-7.1.
///
[Newtonsoft.Json.JsonPropertyAttribute("token_type")]
public string TokenType { get; set; }
/// Gets or sets the lifetime in seconds of the access token.
[Newtonsoft.Json.JsonPropertyAttribute("expires_in")]
public Nullable ExpiresInSeconds { get; set; }
///
/// Gets or sets the refresh token which can be used to obtain a new access token.
/// For example, the value "3600" denotes that the access token will expire in one hour from the time the
/// response was generated.
///
[Newtonsoft.Json.JsonPropertyAttribute("refresh_token")]
public string RefreshToken { get; set; }
///
/// Gets or sets the scope of the access token as specified in http://tools.ietf.org/html/rfc6749#section-3.3.
///
[Newtonsoft.Json.JsonPropertyAttribute("scope")]
public string Scope { get; set; }
///
/// Gets or sets the id_token, which is a JSON Web Token (JWT) as specified in http://tools.ietf.org/html/draft-ietf-oauth-json-web-token
///
[Newtonsoft.Json.JsonPropertyAttribute("id_token")]
public string IdToken { get; set; }
///
/// The date and time that this token was issued, expressed in the system time zone.
/// This property only exists for backward compatibility; it can cause inappropriate behavior around
/// time zone transitions (e.g. daylight saving transitions).
///
[Obsolete("Use IssuedUtc instead")]
[Newtonsoft.Json.JsonPropertyAttribute(Order = 1)] // Serialize this before IssuedUtc, so that IssuedUtc takes priority when deserializing
public DateTime Issued
{
get { return IssuedUtc.ToLocalTime(); }
set { IssuedUtc = value.ToUniversalTime(); }
}
///
/// The date and time that this token was issued, expressed in UTC.
///
///
/// This should be set by the CLIENT after the token was received from the server.
///
[Newtonsoft.Json.JsonPropertyAttribute(Order = 2)]
public DateTime IssuedUtc { get; set; }
///
/// Returns true if the token is expired or it's going to be expired in the next minute.
///
public bool IsExpired(IClock clock)
{
if (AccessToken == null || !ExpiresInSeconds.HasValue)
{
return true;
}
return IssuedUtc.AddSeconds(ExpiresInSeconds.Value - TokenExpiryTimeWindowSeconds) <= clock.UtcNow;
}
///
/// Asynchronously parses a instance from the specified .
///
/// The http response from which to parse the token.
/// The clock used to set the value of the token.
/// The logger used to output messages incase of error.
///
/// The response was not successful or there is an error parsing the response into valid instance.
///
///
/// A task containing the parsed form the response message.
///
public static async Task FromHttpResponseAsync(HttpResponseMessage response, Util.IClock clock, ILogger logger)
{
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var typeName = "";
try
{
if (!response.IsSuccessStatusCode)
{
typeName = nameof(TokenErrorResponse);
var error = NewtonsoftJsonSerializer.Instance.Deserialize(content);
throw new TokenResponseException(error, response.StatusCode);
}
// Gets the token and sets its issued time.
typeName = nameof(TokenResponse);
var newToken = NewtonsoftJsonSerializer.Instance.Deserialize(content);
newToken.IssuedUtc = clock.UtcNow;
return newToken;
}
catch (Newtonsoft.Json.JsonException ex)
{
logger.Error(ex, $"Exception was caught when deserializing {typeName}. Content is: {content}");
throw new TokenResponseException(new TokenErrorResponse
{
Error = "Server response does not contain a JSON object. Status code is: " + response.StatusCode
}, response.StatusCode);
}
}
}
}