GoogleTokenResponse getRefreshToken() return null - authentication

Using OAuth2.0 to authenticate user with access token however GoogleAuthorizationCodeTokenRequest return new access token but it return null for getRefreshToken token following is my code:
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, SCOPES)
.setAccessType("offline")
.setApprovalPrompt("force").build();
String authorizeUrl =
flow.newAuthorizationUrl().setRedirectUri(CALLBACK_URI).build();
System.out.println("Paste this url in your browser: \n" + authorizeUrl + '\n');
GoogleAuthorizationCodeTokenRequest tokenRequest =
flow.newTokenRequest(dfaToken);
tokenRequest.setRedirectUri(CALLBACK_URI);
GoogleTokenResponse tokenResponse = tokenRequest.execute();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(new NetHttpTransport())
.setJsonFactory(new JacksonFactory())
.setClientSecrets(CLIENT_ID, CLIENT_SECRET)
.build();
credential.setFromTokenResponse(tokenResponse);
System.out.println(credential.getAccessToken());
System.out.println(credential.getRefreshToken());
Is there any configuration we need to set up in our project??

Related

IdentityServer4 client - Refreshing access tokens on CookieAuthenticationEvents

I am trying to use refresh token when the access token expires. A similar so question is answered here. And a sample code to renew token by an action
And i end up with the following code in the startup.cs
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "Cookies",
//ExpireTimeSpan = TimeSpan.FromSeconds(100),
AutomaticAuthenticate = true,
AutomaticChallenge = true,
Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = async x =>
{
if (x.Properties?.Items[".Token.expires_at"] == null) return;
var logger = loggerFactory.CreateLogger(this.GetType());
var now = DateTimeOffset.UtcNow;
var tokenExpireTime = DateTime.Parse(x.Properties.Items[".Token.expires_at"]).ToUniversalTime();
var timeElapsed = now.Subtract(x.Properties.IssuedUtc.Value);
var timeRemaining = tokenExpireTime.Subtract(now.DateTime);
if (timeElapsed > timeRemaining)
{
var httpContextAuthentication = x.HttpContext.Authentication;//Donot use the HttpContext.Authentication to retrieve anything, this cause recursive call to this event
var oldAccessToken = await httpContextAuthentication.GetTokenAsync("access_token");
var oldRefreshToken = await httpContextAuthentication.GetTokenAsync("refresh_token");
logger.LogInformation($"Refresh token :{oldRefreshToken}, old access token:{oldAccessToken}");
var disco = await DiscoveryClient.GetAsync(AuthorityServer);
if (disco.IsError) throw new Exception(disco.Error);
var tokenClient = new TokenClient(disco.TokenEndpoint, ApplicationId, "secret");
var tokenResult = await tokenClient.RequestRefreshTokenAsync(oldRefreshToken);
logger.LogInformation("Refresh token requested. " + tokenResult.ErrorDescription);
if (!tokenResult.IsError)
{
var oldIdToken = await httpContextAuthentication.GetTokenAsync("id_token");
var newAccessToken = tokenResult.AccessToken;
var newRefreshToken = tokenResult.RefreshToken;
var tokens = new List<AuthenticationToken>
{
new AuthenticationToken {Name = OpenIdConnectParameterNames.IdToken, Value = oldIdToken},
new AuthenticationToken {Name = OpenIdConnectParameterNames.AccessToken, Value = newAccessToken},
new AuthenticationToken {Name = OpenIdConnectParameterNames.RefreshToken, Value = newRefreshToken}
};
var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) });
var info = await httpContextAuthentication.GetAuthenticateInfoAsync("Cookies");
info.Properties.StoreTokens(tokens);
await httpContextAuthentication.SignInAsync("Cookies", info.Principal, info.Properties);
}
x.ShouldRenew = true;
}
else
{
logger.LogInformation("Not expired");
}
}
}
});
The client setup is as follows
AllowAccessTokensViaBrowser = true,
RefreshTokenUsage = TokenUsage.ReUse,
RefreshTokenExpiration = TokenExpiration.Sliding,
AbsoluteRefreshTokenLifetime = 86400,
AccessTokenLifetime = 10,
AllowOfflineAccess = true,
AccessTokenType = AccessTokenType.Reference
After successfully login, i am getting a 401 for every other request. And the log says
[Identity Server]2017-07-04 10:15:58.819 +01:00 [Debug]
"TjpIkvHQi../cfivu6Nql5ADJJlZRuoJV1QI=" found in database: True
[Identity Server]2017-07-04 10:15:58.820 +01:00 [Debug]
"reference_token" grant with value:
"..9e64c1235c6675fcef617914911846fecd72f7b372" found in store, but has
expired.
[Identity Server]2017-07-04 10:15:58.821 +01:00 [Error] Invalid
reference token. "{ \"ValidateLifetime\": true,
\"AccessTokenType\": \"Reference\", \"TokenHandle\":
\"..9e64c1235c6675fcef617914911846fecd72f7b372\" }"
[Identity Server]2017-07-04 10:15:58.822 +01:00 [Debug] Token is
invalid.
[Identity Server]2017-07-04 10:15:58.822 +01:00 [Debug] Creating
introspection response for inactive token.
[Identity Server]2017-07-04 10:15:58.822 +01:00 [Information] Success
token introspection. Token status: "inactive", for API name: "api1"
Any help would by highly appreciated
UPDATE:
Basically, when the token expires i get a System.StackOverflowException on the following line
var tokenExpireTime = DateTime.Parse(x.Properties.Items[".Token.expires_at"]).ToUniversalTime();
UPDATE 2:
Do not use HttpContext.Authentication to retrieve anything. Check my answer below to find the working implementaion
I was working on this for last two days and could not make this work. Funnily, after posting the question here, within 2 hours I make it working :)
Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = async x =>
{
if (x.Properties?.Items[".Token.expires_at"] == null) return;
var now = DateTimeOffset.UtcNow;
var tokenExpireTime = DateTime.Parse(x.Properties.Items[".Token.expires_at"]).ToUniversalTime();
var timeElapsed = now.Subtract(x.Properties.IssuedUtc.Value);
var timeRemaining = tokenExpireTime.Subtract(now.DateTime);
WriteMessage($"{timeRemaining} and elapsed at {timeElapsed}");
if (timeElapsed > timeRemaining)
{
var oldAccessToken = x.Properties.Items[".Token.access_token"];
var oldRefreshToken = x.Properties.Items[".Token.refresh_token"];
WriteMessage($"Refresh token :{oldRefreshToken}, old access token {oldAccessToken}");
var disco = await DiscoveryClient.GetAsync(AuthorityServer);
if (disco.IsError) throw new Exception(disco.Error);
var tokenClient = new TokenClient(disco.TokenEndpoint, ApplicationId, "secret");
var tokenResult = await tokenClient.RequestRefreshTokenAsync(oldRefreshToken);
if (!tokenResult.IsError)
{
var oldIdToken = x.Properties.Items[".Token.id_token"];//tokenResult.IdentityToken
var newAccessToken = tokenResult.AccessToken;
var newRefreshToken = tokenResult.RefreshToken;
var tokens = new List<AuthenticationToken>
{
new AuthenticationToken {Name = OpenIdConnectParameterNames.IdToken, Value = oldIdToken},
new AuthenticationToken {Name = OpenIdConnectParameterNames.AccessToken, Value = newAccessToken},
new AuthenticationToken {Name = OpenIdConnectParameterNames.RefreshToken, Value = newRefreshToken}
};
var expiresAt = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);
tokens.Add(new AuthenticationToken { Name = "expires_at", Value = expiresAt.ToString("o", CultureInfo.InvariantCulture) });
x.Properties.StoreTokens(tokens);
WriteMessage($"oldAccessToken: {oldAccessToken}{Environment.NewLine} and new access token {newAccessToken}");
}
x.ShouldRenew = true;
}
}
}
Basically httpContextAuthentication.GetTokenAsync make this recursive, for that reason StackOverflowException occured.
Please let me know if this implementation has any issue

create user accounts in office 365 using c#.net code dynamically

I want a sample application in c#.net which can create users in Office 365 using Microsoft API .
I wish to do it in code, not using Powershell.
You can use the Microsoft Graph API - Create User:
Register a Native Client App on Azure AD, assign the "Microsoft Graph" > "Read and Write Directory Data" permission.
string authority = "https://login.windows.net/yourdomain.onmicrosoft.com";
string clientId = "{app_client_id}";
Uri redirectUri = new Uri("http://localhost");
string resourceUrl = "https://graph.microsoft.com";
HttpClient client = new HttpClient();
AuthenticationContext authenticationContext = new AuthenticationContext(authority, false);
AuthenticationResult authenticationResult = authenticationContext.AcquireToken(resourceUrl,
clientId, redirectUri, PromptBehavior.Always);
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + authenticationResult.AccessToken);
string content = #"{
'accountEnabled': true,
'displayName': 'testuser',
'mailNickname': 'test',
'passwordProfile': {
'forceChangePasswordNextSignIn': true,
'password': 'pass#wd12345'
},
'userPrincipalName': 'testuser#yourdomain.onmicrosoft.com'
}";
var httpContent = new StringContent(content, Encoding.GetEncoding("utf-8"), "application/json");
var response = client.PostAsync("https://graph.microsoft.com/v1.0/users", httpContent).Result;
Console.WriteLine(response.Content.ReadAsStringAsync().Result);

Update claims after login with identityserver3 2.1.1

We need to update users claims after they log in to our website. This is caused by changes in the users licenses done by another part of our system.
However I am not able to comprehend how to update the claims without logout/login.
Rigth now this is our client setup
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
//user validation host
Authority = UrlConstants.BaseAddress,
//Client that the user is validating against
ClientId = guid,//if not convertet to Gui the compare from the server fails
RedirectUri = UrlConstants.RedirectUrl,
PostLogoutRedirectUri = UrlConstants.RedirectUrl,
ResponseType = "code id_token token",
Scope = "openid profile email roles licens umbraco_api umbracoaccess",
UseTokenLifetime = false,
SignInAsAuthenticationType = "Cookies",
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async n =>
{
_logger.Info("ConfigureAuth", "Token valdidated");
var id = n.AuthenticationTicket.Identity;
var nid = new ClaimsIdentity(
id.AuthenticationType,
Constants.ClaimTypes.GivenName,
Constants.ClaimTypes.Role);
// get userinfo data
var uri = new Uri(n.Options.Authority + "/connect/userinfo");
var userInfoClient = new UserInfoClient(uri,n.ProtocolMessage.AccessToken);
var userInfo = await userInfoClient.GetAsync();
userInfo.Claims.ToList().ForEach(ui => nid.AddClaim(new Claim(ui.Item1, ui.Item2)));
var licens = id.FindAll(LicenseScope.Licens);
nid.AddClaims(licens);
// keep the id_token for logout
nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
_logger.Info("ConfigureAuth", "AuthenticationTicket created");
},
RedirectToIdentityProvider = async n =>
{
// if signing out, add the id_token_hint
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token").Value;
_logger.Debug("ConfigureAuth", "id_token for logout set on request");
_logger.Debug("ConfigureAuth", "Old PostLogoutRedirectUri: {0}", n.ProtocolMessage.PostLogoutRedirectUri.ToString());
n.ProtocolMessage.IdTokenHint = idTokenHint;
var urlReferrer = HttpContext.Current.Request.UrlReferrer.ToString();
if (!urlReferrer.Contains("localhost"))
{
n.ProtocolMessage.PostLogoutRedirectUri = GetRedirectUrl();
}
else
{
n.ProtocolMessage.PostLogoutRedirectUri = urlReferrer;
}
_logger.Debug("ConfigureAuth", string.Format("Setting PostLogoutRedirectUri to: {0}", n.ProtocolMessage.PostLogoutRedirectUri.ToString()));
}
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.AuthenticationRequest)
{
n.ProtocolMessage.RedirectUri = GetRedirectUrl2();
n.ProtocolMessage.AcrValues = GetCurrentUmbracoId();
_logger.Debug("ConfigureAuth", string.Format("Setting RedirectUri to: {0}", n.ProtocolMessage.RedirectUri.ToString()));
}
},
}
});
We get our custom claims in SecurityTokenValidated
var licens = id.FindAll(LicenseScope.Licens);
nid.AddClaims(licens);
I do not follow how to get this without doing a login? Any help is highly appreciated.
That's a reminder that you should not put claims into tokens that might change during the lifetime of the session.
That said - you can set a new cookie at any point in time.
Reach into the OWIN authentication manager and call the SignIn method. Pass the claims identity that you want to serialize into the cookie.
e.g.
Request.GetOwinContext().Authentication.SignIn(newIdentity);

azure active directory graph REST api call through SP.WebRequestInfo on SharePoint Online

Trying to make a REST call through SharePoint's SP.WebRequestInfo.
I'm getting the error "The remote server returned the following error while establishing a connection - 'Unauthorized'." trying to call https://graph.windows.net/[Client]/users?api-version=2013-11-0.
I've successfully retrieved a access token.
Can you help me out why i'm getting this error?
Here is the code i'm using:
var url = "https://graph.windows.net/xxx/users/?api-version=2013-11-08";
var context = SP.ClientContext.get_current();
var request = new SP.WebRequestInfo();
request.set_url(url);
request.set_method("GET");
request.set_headers({
"Authorization": token.token_type + " " + token.access_token,
"Content-Type": "application/json"
});
var response = SP.WebProxy.invoke(context, request);
context.executeQueryAsync(successHandler, errorHandler);
function successHandler() {
if (response.get_statusCode() == 200) {
var responseBody = JSON.parse(response.get_body());
deferred.resolve(responseBody);
} else {
var httpCode = response.get_statusCode();
var httpText = response.get_body();
deferred.reject(httpCode + ": " + httpText);
}
}
The code for retrieving the token is:
this.getToken = function (clientId, clientSecret) {
var deferred = $q.defer();
var resource = "https://graph.windows.net";
var formData = "grant_type=client_credentials&resource=" + encodeURIComponent(resource) + "&client_id=" + encodeURIComponent(clientId) + "&client_secret=" + encodeURIComponent(clientSecret);
var url = "https://login.windows.net/xxxxxx.onmicrosoft.com/oauth2/token?api-version=1.0";
var context = SP.ClientContext.get_current();
var request = new SP.WebRequestInfo();
request.set_url(url);
request.set_method("POST");
request.set_body(formData);
var response = SP.WebProxy.invoke(context, request);
context.executeQueryAsync(successHandler, errorHandler);
function successHandler() {
if (response.get_statusCode() == 200) {
var token = JSON.parse(response.get_body());
deferred.resolve(token);
} else {
var httpCode = response.get_statusCode();
var httpText = response.get_body();
deferred.reject(httpCode + ": " + httpText);
}
}
function errorHandler() {
deferred.reject(response.get_body());
}
return deferred.promise;
};
Erik, something is strange here - you are using the client credential flow from a JavaScript client - this reveals the secret issued to the client app to the user of the JS app.
The client credential flow also requires the directory admin to grant directory read permission to the client application - not sure if this was already configured - nevertheless it must only be used with a confidential client, not a public client like a JS app.
Azure AD does not yet implement the implicit_grant oauth flow using which a JS client app can acquire an access token on behalf of the user over redirect binding (in the fragment). This is a hugh-pro requirement that we're working on - stay tuned.

Shopify authentication using the google app script Class OAuthConfig

I am trying to connect with my shopify shop through the google javascrip. The schema for authentication should be something similar to the one you can find on google documentation for twitter. I'am trying the following code, but I always get the error:{"errors":"[API] Invalid API key or access token (unrecognized login or wrong password)"}
function getInfofromshopify() {
var handle = "01-02-0316_cmt_utensili"
var urljson ="https://mysitename.myshopify.com/admin/products.json?handle="+handle;
var oAuthConfig = UrlFetchApp.addOAuthService("shopify");
oAuthConfig.setAccessTokenUrl("https://mysitename.myshopify.com/admin/oauth/access_token");
oAuthConfig.setRequestTokenUrl("https://mysitename.myshopify.com/admin/oauth/access_token");
oAuthConfig.setAuthorizationUrl("https://mysitename.myshopify.com/admin/oauth/authorize");
oAuthConfig.setConsumerKey(API_KEY);
oAuthConfig.setConsumerSecret(Shared_secret);
var options =
{
"oAuthServiceName" : "shopify",
"oAuthUseToken" : "always"
};
var response = UrlFetchApp.fetch(urljson,options);
var responsestr = response.getContentText();
var result = Utilities.jsonParse(responsestr)
}
This worked for me:
var url = "https://<YOUR_SHOP>.myshopify.com/admin/products.json";
var username = "<YOUR_SHOPIFY_API_KEY>";
var password = "<YOUR_SHOPIFY_API_PASSWORD>";
var response = UrlFetchApp.fetch(url, {"method":"get", "headers": {"Authorization": "Basic " + Utilities.base64Encode(username + ":" + password)}});