OneDrive Service don't get a refresh token - onedrive

I use Xamarin.Auth to authenticate with the OneDrive Service. This worked fine for a while now, but I seems there where changes on the service so it stopped working..
I upgraded to the new version 2.0 and try to make it work again. The Initial authentication works well so far. But after a while it always started to crash. I realized that there isn't any refrehs token sent back from the onedrive service.
This is the code to call the Auth UI:
private Task<IDictionary<string, string>> ShowWebView()
{
var tcs = new TaskCompletionSource<IDictionary<string, string>>();
var auth = new OAuth2Authenticator(ServiceConstants.MSA_CLIENT_ID,
string.Join(",", ServiceConstants.Scopes),
new Uri(GetAuthorizeUrl()),
new Uri(ServiceConstants.RETURN_URL));
auth.Completed +=
(sender, eventArgs) =>
{
tcs.SetResult(eventArgs.IsAuthenticated ? eventArgs.Account.Properties : null);
};
var intent = auth.GetUI(Application.Context);
intent.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(intent);
return tcs.Task;
}
private string GetAuthorizeUrl()
{
var requestUriStringBuilder = new StringBuilder();
requestUriStringBuilder.Append(ServiceConstants.AUTHENTICATION_URL);
requestUriStringBuilder.AppendFormat("?{0}={1}", ServiceConstants.REDIRECT_URI,
ServiceConstants.RETURN_URL);
requestUriStringBuilder.AppendFormat("&{0}={1}", ServiceConstants.CLIENT_ID,
ServiceConstants.MSA_CLIENT_ID);
requestUriStringBuilder.AppendFormat("&{0}={1}", ServiceConstants.SCOPE,
WebUtility.UrlEncode(string.Join(" ", ServiceConstants.Scopes)));
requestUriStringBuilder.AppendFormat("&{0}={1}", ServiceConstants.RESPONSE_TYPE, ServiceConstants.CODE);
return requestUriStringBuilder.ToString();
}
The Authorize URI is:
https://login.live.com/oauth20_authorize.srf?redirect_uri=https://login.live.com/oauth20_desktop.srf&client_id=["id"]&scope=onedrive.readwrite+wl.offline_access+wl.signin&response_type=code
The response I get contains 6 Elements:
access_token: "EwAIA..."
token_type: "bearer"
expires_in: "3600"
scope: "onedrive.readwrite wl.offline_access wl.signin wl.basic wl.skydrive wl.skydrive_update onedrive.readonly"
user_id: "41...."
state: "ykjfmttehzjebqtp"
When I check it with the Documentation (https://dev.onedrive.com/auth/msa_oauth.htm) I can't see what's wrong here. Any ideas?

I called wrong constructor. This one works:
authenticator = new OAuth2Authenticator(ServiceConstants.MSA_CLIENT_ID,
ServiceConstants.MSA_CLIENT_SECRET,
string.Join(",", ServiceConstants.Scopes),
new Uri(ServiceConstants.AUTHENTICATION_URL),
new Uri(ServiceConstants.RETURN_URL),
new Uri(ServiceConstants.TOKEN_URL));
With these constants:
Scopes = {"onedrive.readwrite", "wl.offline_access", "wl.signin"};
RETURN_URL = "https://login.live.com/oauth20_desktop.srf";
AUTHENTICATION_URL = "https://login.live.com/oauth20_authorize.srf";
TOKEN_URL = "https://login.live.com/oauth20_token.srf";

Related

How to get microsoft account profile photo after login with application in mvc

With the help of claimprincipal, I'm able to get the details of signedin user as below but its not giving any pic related information as google does:
https://apis.live.net/v5.0/{USER_ID}/picture?type=large
which says The URL contains the path '{user_id}', which isn't supported.
Even tried
https://graph.microsoft.com/v1.0/me/photo/$value
which is asking for access token, but I am not sure what have to be passed
string userName = ClaimsPrincipal.Current.FindFirst("name").Value;
string userEmail = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email).Value;
string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
Wanted an image which was added in any outlook account
For Image to show.. We have to use beared token and have to convert the image into memory stream and then have to used it.. I have done it in below ways. Hope this help ...
var client = new RestClient("https://login.microsoftonline.com/common/oauth2/token");
var request = new RestRequest(Method.POST);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", $"code={code}&client_id={OutClientId}&client_secret={SecretKey}&redirect_uri={OutRedirectUrl}&grant_type=authorization_code", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Token jsonContent = JsonConvert.DeserializeObject<Token>(response.Content);
var Token = jsonContent.AccessToken;
var TokenType = jsonContent.TokenType;
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);
HttpResponseMessage response1 = await httpClient.GetAsync("https://graph.microsoft.com/v1.0/me/photos/96x96/$value");
if (response1.StatusCode == HttpStatusCode.OK)
{
using (Stream responseStream = await response1.Content.ReadAsStreamAsync())
{
MemoryStream ms = new MemoryStream();
responseStream.CopyTo(ms);
byte[] buffer = ms.ToArray();
string result = Convert.ToBase64String(buffer);
HttpContext.Session[AppConstants.UserImage] = String.Format("data:image/gif;base64,{0}", result);
responseStream.Close();
}
}
Is there any reason you are using the live.net apis? Instead of the Microsoft Graph APIs? Microsoft Graph APIs are the future for all user data within Microsoft 365 consumer and commercial accounts.
You can get the Users photo very easily as described here https://learn.microsoft.com/en-us/graph/api/profilephoto-get?view=graph-rest-1.0
GET /me/photo/$value
As you are using ASP.NET MVC, there is an SDK you can use that makes this very easy too.
https://learn.microsoft.com/en-us/graph/sdks/sdks-overview?context=graph%2Fapi%2F1.0&view=graph-rest-1.0

Windows Phone Silverlight request does not update

I'm quite new to the Windows Phone dev and I have to do an application to communicate with a Restful API. Everything works fine to get the informations back from the API but my problem occurs when I try to update the content. For example, I have a profile and I try to update the user's information (change the city let's say). On the server side I can see that my update worked properly but when I go back to my profile in my WP app nothing has changed, the city is still the same as the old one. This is my code :
public MainPage()
{
InitializeComponent();
this.ApplicationBar = this.Resources["HomeBar"] as ApplicationBar;
Requester requester = new Requester();
requester.initGetRequest("/me/", GetResponseCallback, true);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string read = streamRead.ReadToEnd();
GlobalData.GetInstance().user = JsonConvert.DeserializeObject<MeClass>(read);
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(read);
});
//Create the profile and stuff
streamResponse.Close();
streamRead.Close();
response.Close();
}
catch (WebException webException)
{
HttpStatusCode status = ((HttpWebResponse)webException.Response).StatusCode;
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(status.ToString());
});
}
}
I figured out that the string 'read' is always equal to the old one, even after the update so this is why the content is not updated but how can the response be exactly the same as before, even if the update worked fine on the server side (if I check in Postman after my update, I can see that my city is the new one). If I restart my app I can see the update.
I can also show you my initGetRequest() :
public void initGetRequest(String endPoint, Action<IAsyncResult> callback, Boolean header)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + endPoint);
if (header == true)
request.Headers["Authorization"] = GlobalData.GetInstance().Header;
request.BeginGetResponse(new AsyncCallback(callback), request);
}
Thank you for your help !
I finally found why my request was still the same even after the update. The HttpWebRequest uses a cache by default. I only added a small bit of code before calling my request :
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + endPoint);
if (header == true)
request.Headers["Authorization"] = GlobalData.GetInstance().Header;
request.Headers[HttpRequestHeader.IfModifiedSince] = DateTime.UtcNow.ToString();
request.BeginGetResponse(new AsyncCallback(callback), request);
I had no idea about that cache so I hope this answer will help someone having the same issue !

Marketo rest Api create lead

I have a question about this create/Update leads API, http://developers.marketo.com/documentation/rest/createupdate-leads/.
There is no sample code for C# or JAVA. Only ruby available. So I have to try it by myself. But I always get null return from the response.
Here is my code:
private async Task<CreateLeadResponseResult> CreateLead(string token)
{
string url = String.Format(marketoInstanceAddress+"/rest/v1/leads.json?access_token={0}", token);
var fullUri = new Uri(url, UriKind.Absolute);
CreateLeadResponseResult createLeadResponse = new CreateLeadResponseResult();
CreateLeadInput input = new CreateLeadInput { email = "123#123.com", lastName = "Lee", firstName = "testtesttest", postCode = "00000" };
CreateLeadInput input2 = new CreateLeadInput { email = "321#gagaga.com", lastName = "Lio", firstName = "ttttttt", postCode = "00000" };
List<CreateLeadInput> inputList = new List<CreateLeadInput>();
inputList.Add(input);
inputList.Add(input2);
CreateLeadRequest createLeadRequest = new CreateLeadRequest() { input = inputList };
JavaScriptSerializer createJsonString = new JavaScriptSerializer();
string inputJsonString = createJsonString.Serialize(createLeadRequest);
using (var client = new HttpClient())
{
HttpResponseMessage response = await client.PostAsJsonAsync(fullUri.OriginalString, inputJsonString).ConfigureAwait(false);
// I can see the JSON string is in the message body in debugging mode.
if (response.IsSuccessStatusCode)
{
createLeadResponse = await response.Content.ReadAsAsync<CreateLeadResponseResult>();
}
else
{
if (response.StatusCode == HttpStatusCode.Forbidden)
throw new AuthenticationException("Invalid username/password combination.");
else
throw new ApplicationException("Not able to get token");
}
}
return createLeadResponse;}
//get null here.
Thank you.
-C.
The best way to debug this is to capture the exact URL, parameters and JSON that are submitted by your app and try submitting those manually via a tool like Postman (Chrome plug-in) or SOAP UI. Then you see the exact error message, which you can look up here: http://developers.marketo.com/documentation/rest/error-codes/. Based on that you can update your code. I don't know much about Java, but this is how I got my Python code to work.
Your example code was really helpful in getting my own implementation off the ground. Thanks!
After playing with it for a bit, I realized that the JavaScriptSerializer step is unnecessary since PostAsJsonAsync automatically serializes whatever object you pass to it. The double serialization prevents Marketo's API from processing the input.
Also, I agree with Jep that Postman is super helpful. But in the case of this error, Postman was working fine (using the contents of inputJsonString) but my C# code still didn't work properly. So I temporarily modified the code to return a dynamic object instead of a CreateLeadResponseResult. In debugging mode this allowed me to see fields that were discarded because they didn't fit the CreateLeadResponseResult type, which led me to the solution above.

Authenticating with Facebook for Mobile Services in Azure

I am having trouble with facebook authentication for Mobile Services in Azure.
To be more specific, I already have an application that is using Facebook C# SDK and it works fine. I can log on, fetch list of my friends and so. I want to keep using this SDK, but I also want to authenticate for Azure Mobile Service.
So, my plan was, log on with Facebook C# SDK (as I already do today), get the authentication token, and pass it to the MobileServiceClient.LoginAsync() - function. That way, I can still have all the nice features in Facebook C# SDK, and also use the built in authentication system in Mobile Services for Azure.
var client = new FacebookClient();
dynamic parameters = new ExpandoObject();
parameters.client_id = App.FacebookAppId;
parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
parameters.response_type = "token";
parameters.display = "popup";
var loginUrl = client.GetLoginUrl(parameters);
WebView.Navigate(loginUrl);
When load is complete, followin is executed:
FacebookOAuthResult oauthResult;
if (client.TryParseOAuthCallbackUrl(e.Uri, out oauthResult) && oauthResult.IsSuccess)
{
var accessToken = oauthResult.AccessToken;
var json = JsonObject.Parse("{\"authenticationToken\" : \"" + accessToken + "\"}");
var user = await App.MobileService.LoginAsync(MobileServiceAuthenticationProvider.Facebook, json);
}
However, I get this exception when I call the last line of code above:
MobileServiceInvalidOperationException, "Error: The POST Facebook login request must specify the access token in the body of the request."
I cannot find any information on how to format the accesstoken, I have tried a lot of different keys (instead of "authenticationToken" as you see in my sample). I also have tried just to pass the accesstoken string, but nothing seem to work.
Also, if I use the MobileServiceClient.LoginAsync() for making a brand new login, it works just fine, but it seem silly to force users to log on twice.
Any help is greatly appreciated!
The format expected for the object is {"access_token", "the-actual-access-token"}. Once the login is completed using the Facebook SDK, the token is returned in the fragment with that name, so that's what the Azure Mobile Service expects.
BTW, this is a code which I wrote, based on your snippet, which works. It should handle failed cases better, though, but for the token format, this should be enough
private void btnLoginFacebookToken_Click_1(object sender, RoutedEventArgs e)
{
var client = new Facebook.FacebookClient();
dynamic parameters = new ExpandoObject();
parameters.client_id = "MY_APPLICATION_CLIENT_ID";
parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
parameters.response_type = "token";
parameters.display = "popup";
var uri = client.GetLoginUrl(parameters);
this.webView.LoadCompleted += webView_LoadCompleted;
this.webView.Visibility = Windows.UI.Xaml.Visibility.Visible;
this.webView.Navigate(uri);
}
async void webView_LoadCompleted(object sender, NavigationEventArgs e)
{
AddToDebug("NavigationMode: {0}", e.NavigationMode);
AddToDebug("Uri: {0}", e.Uri);
string redirect_uri = "https://www.facebook.com/connect/login_success.html";
bool close = (e.Uri.ToString().StartsWith(redirect_uri));
if (close)
{
this.webView.LoadCompleted -= webView_LoadCompleted;
this.webView.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
string fragment = e.Uri.Fragment;
string accessToken = fragment.Substring("#access_token=".Length);
accessToken = accessToken.Substring(0, accessToken.IndexOf('&'));
JsonObject token = new JsonObject();
token.Add("access_token", JsonValue.CreateStringValue(accessToken));
try
{
var user = await MobileService.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token);
AddToDebug("Logged in: {0}", user.UserId);
}
catch (Exception ex)
{
AddToDebug("Error: {0}", ex);
}
}
}

Can't Query Google Analytics Reports API Using OAuth 2

I am trying to to use the latest version of the Report API using OAuth 2. It doesn't appear that there are many people using this version yet, so it has been really hard to find examples.
I have a refresh token, which I am using to generate an access token.
private AnalyticsService getAnalyticsService()
{
AuthorizationServerDescription description = new AuthorizationServerDescription();
description.TokenEndpoint = new Uri(login.TokenEndpoint);
description.AuthorizationEndpoint = new Uri(login.AuthorizationEndpoint);
WebServerClient client = new WebServerClient(description, login.ClientId, login.ClientSecret);
OAuth2Authenticator<WebServerClient> authenticator = new OAuth2Authenticator<WebServerClient>(client, authenticate);
AnalyticsService service = new AnalyticsService(authenticator);
return service;
}
private IAuthorizationState authenticate(WebServerClient client)
{
string[] scopes = new string[] { login.ScopeUrl }; // not sure if this is necessary
IAuthorizationState state = new AuthorizationState(scopes) { RefreshToken = login.RefreshToken };
client.RefreshToken(state);
return state;
}
This appears to be working just fine:
{
"access_token" : "ya29.AHES6ZQy67SSLHWJWGWcLbLn69yKfq59y6dTHDf4ZoH9vHY",
"token_type" : "Bearer",
"expires_in" : 3600
}
However, when I do a request, I am getting an error. For example, here
is a query that results in an error:
AnalyticsService service = getAnalyticsService();
ManagementResource.ProfilesResource.ListRequest request = service.Management.Profiles.List("~all", "~all");
return request.Fetch();
This is the error I get:
{"error":{"errors":[{"domain":"global","reason":"authError","message":"Invalid
Credentials","locationType":"header","location":"Authorization"}],"code":401,"message":"Invalid
Credentials"}}
I have tried other queries, providing valid profile IDs. However, I am
always getting a 401 error, saying I'm not authorized. I am having
trouble finding examples where people are using this code. It could be
something simple like a bad URL or something. Unfortunately, I have no
way to telling. It seems strange that I can get an access token, but I
can't seem to perform any queries.
With OAuth 2, the scope changed from:
https://www.google.com/analytics/feeds/
to:
https://www.googleapis.com/auth/analytics.readonly
You are getting the authentication error because you were trying to get access without the proper scope.
Quick and easy fix.