I have a Windows 8 Store Application and I want to add Azure Authentication to it. I have followed the example in the MSDN page. However, the following line is giving me issues:
MobileServiceUser loginResult = await App.MobileService.LoginAsync(result.Session.AuthenticationToken);
The error is: App does not contain a definition for MobileService. When does an instance of MobileService get added to the App class?
I have added references to the Microsoft.Live and Azure Mobile Services libraries. Here is the entire Authenticate function:
private async System.Threading.Tasks.Task Authenticate()
{
LiveAuthClient liveIdClient = new LiveAuthClient("<< INSERT REDIRECT DOMAIN HERE >>");
while (session == null)
{
// Force a logout to make it easier to test with multiple Microsoft Accounts
if (liveIdClient.CanLogout)
liveIdClient.Logout();
LiveLoginResult result = await liveIdClient.LoginAsync(new[] { "wl.basic" });
if (result.Status == LiveConnectSessionStatus.Connected)
{
session = result.Session;
LiveConnectClient client = new LiveConnectClient(result.Session);
LiveOperationResult meResult = await client.GetAsync("me");
MobileServiceUser loginResult = await App.MobileService.LoginAsync(result.Session.AuthenticationToken);
string title = string.Format("Welcome {0}!", meResult.Result["first_name"]);
var message = string.Format("You are now logged in - {0}", loginResult.UserId);
var dialog = new MessageDialog(message, title);
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
else
{
session = null;
var dialog = new MessageDialog("You must log in.", "Login Required");
dialog.Commands.Add(new UICommand("OK"));
await dialog.ShowAsync();
}
}
}
You have to add the class yourself.
On the Azure Mobile Services "Getting Started Page", select "Windows Store", and then "CONNECT AN EXISTING WINDOWS STORE APP" (don't mean to shout, it's literally in all caps on the page like that!).
It will tell you to do the following:
Add "using Microsoft.WindowsAzure.MobileServices;", then copy and
paste the following code into your App.xaml.cs file:
public static MobileServiceClient MobileService = new MobileServiceClient(
"https://[your website].azure-mobile.net/",
"[your key]"
);
Related
I want to log in and get cookies in xamarin forms. At the same time, the data will remain until I log out, but when I log out, the data I keep in the cookie will be reset. how can i do it?(Actually, I can login now, but I don't understand the logic of saving the information in the cookie and logging out.)
EDIT : I want to do it with using AppShell
if (Connectivity.NetworkAccess == NetworkAccess.Internet)
{
var userName = tbName.Text;
var password = tbPassword.Text;
var serviceUrl = "API";
var paramList = new List<ServiceParameterObject>();
paramList.Add(new ServiceParameterObject("_userCode", userName));
paramList.Add(new ServiceParameterObject("_userPassword", password));
var apiResult = ApiResult.SendPostRequestFromBody(serviceUrl, paramList);
if (apiResult.Status)
{
var user = JsonConvert.DeserializeObject<User>(apiResult.Message);
//Preferences.Set("userName", tbName.Text);
//Preferences.Set("Password", tbPassword.Text);
Preferences.Set("userId", user.Id.ToString());
var userIdCookie = Preferences.Get("userId", String.Empty);
await Shell.Current.GoToAsync($"//{nameof(HomePage)}");
}
else
{
await DisplayAlert("Uyarı", "Kullanıcı Adınız veya Şifreniz hatalıdır. Lütfen tekrar deneyiniz.", "Tamam");
}
}
else
{
await DisplayAlert("Uyarı", "İnternet bağlantınız yok. Lütfen Bağlantınızı kontrol edip tekrar deneyiniz", "Tamam");
}
Have your looked into Xamarin forms' Secure Storage ?
I think this could the easiest way for you to achieve your desired implementation.
Upon launch, look into storage to see if any information is stored (your cookie or any other auth information)
a) If Nothing is stored, run login and store information
b) If something is stored, grant access to app and fetch stored info
Upon logout, simply clear the stored cookie
I am attempting to query Azure Active Directory User information using Microsoft Graph. I can authenticate fine but when I attempt to query user information client.Users my application hangs indefinitely: no timeout, no error, just hangs. I found this post however the suggestions there did not help me.
public bool GetUserByUniqueID(string uid, out GraphUser user)
{
bool ret = false;
user = new GraphUser();
if (Authenticate(out AuthToken token))
{
GraphServiceClient client = GetGraphServiceClient(token);
// The below code hangs indefinitely
User user = client.Users[uid].Request().Select(GraphProperties).GetAsync().GetAwaiter().GetResult();
if (user != null)
{
MapGraphUser(ret, user);
ret = true;
}
}
return ret;
}
private bool Authenticate(out AuthToken token)
{
bool ret = false;
token = new AuthToken();
string url = $"https://login.microsoftonline.com/{_tenant}/oauth2/v2.0/token";
RestClient client = new RestClient(url);
RestRequest request = new RestRequest(Method.POST);
request.Parameters.Add(new Parameter("grant_type", _grantType, ParameterType.GetOrPost));
request.Parameters.Add(new Parameter("scope", _scope, ParameterType.GetOrPost));
request.Parameters.Add(new Parameter("client_secret", _clientSecret, ParameterType.GetOrPost));
request.Parameters.Add(new Parameter("client_id", _clientId, ParameterType.GetOrPost));
IRestResponse response = client.Execute<AuthToken>(request);
if (response.StatusCode == HttpStatusCode.OK)
{
token = JsonConvert.DeserializeObject<AuthToken>(response.Content);
ret = true;
}
return ret;
}
Update 5/2/2019
Reverting Microsoft.Graph and Microsoft.Graph.Core to version 1.12 allows me to call .GetAwaiter().GetResult() within a synchronous context.
Update 11/18/2020
I have refactored my code to use async/await pattern with the latest version of Microsoft.Graph and Microsoft.Graph.Core.
public async Task<GraphUser> GetUserByUniqueID(string uid)
{
GraphUser ret = new GraphUser();
if (Authenticate(out AuthToken token))
{
GraphServiceClient client = GetGraphServiceClient(token);
User user = await client.Users[uid].Request().Select(GraphProperties).GetAsync();
if (user != null)
{
MapGraphUser(ret, user);
ret.Found = true;
}
}
return ret;
}
I was having the same issue. I found on another article somewhere that it had something to do with two task waiting to finish at once. i cant find that article now.
For me .GetAwaiter().GetResult(); was working within a scheduled job but not as a manual button press task.
as a result of playing around with it. What worked for me was replacing .GetAwaiter().GetResult() with await. (i'm not sure why this fixed it but it did)
From:
var results = graphServiceClient.Users[uid].Request().GetAsync().GetAwaiter().GetResult();
To:
var results = await graphServiceClient.Users[uid].Request().GetAsync();
Hope this helps someone in the future
I'm having the same issue with NPM package of the Graph API. Reverted to plain old request-promise. Now it's not stuck but does not always find the members of a group. Using beta version of the API works fine
I had the same issue when trying to get a list of sites, but I was using Microsoft.Graph V 4.47.0 and Microsoft.Graph.Core V 2.0.14, from within a MVC Web project. I was also using await.
var drives = await graphClient.Sites["root"].Lists
.Request()
.GetAsync();
The above just hangs. Changing to:
var drives = graphClient.Sites["root"].Lists
.Request()
.GetAsync()
.GetAwaiter()
.GetResult();
works as expected.
Full Code:
public async Task GetDrives(GraphServiceClient graphClient)
{
AuthenticationConfig config = AuthenticationConfig.ReadFromJsonFile("appsettings.json");
O365Drives = new List<MyDriveInfo>();
var drives = graphClient.Sites["root"].Lists
.Request()
.GetAsync()
.GetAwaiter()
.GetResult();
foreach (var item in drives)
{
O365Drives.Add(new MyDriveInfo
{
Id = item.Id,
Name = item.Name,
WebUrl = item.WebUrl,
CreatedOn = item.CreatedDateTime,
ModifiedOn = item.LastModifiedDateTime
});
}
}
The above is called by firing an Ajax POST request when clicking on a button.
In another project, a console app, using Microsoft.Graph V 4.34.0 and Microsoft.Graph.Core V 2.0.9
var drives = await graphClient.Sites["root"].Lists
.Request()
.GetAsync();
Works as expected.
Full Code:
private static async Task GetDrives(GraphServiceClient graphClient)
{
AuthenticationConfig config = AuthenticationConfig.ReadFromJsonFile("appsettings.json");
myFileInfo.O365Drives = new List<MyDriveInfo>();
var drives = await graphClient.Sites[$"{config.SiteID}"].Lists
.Request()
.GetAsync();
foreach(var item in drives)
{
myFileInfo.O365Drives.Add(new MyDriveInfo
{
Id = item.Id,
Name = item.Name,
WebUrl = item.WebUrl,
CreatedOn = item.CreatedDateTime,
ModifiedOn = item.LastModifiedDateTime
});
}
}
The above is called by either running the console app manually or from a scheduled task.
I just thought I'd post my findings for the newer versions of Microsoft.Graph for anyone else having similar issues.
I am using TweetSharp to send tweets to users (currently testing it) however it keeps coming back with Bad Authentication Data
{"errors":[{"code":215,"message":"Bad Authentication data."}]}
I have checked my app settings and it has full read and write access. I have also tried to regenerate my consumer keys but still not luck.
here is my code
public ActionResult AccessToken()
{
string oauth_consumer_key = "<consumer key>";
string oauth_consumer_secret = "<consumer secret>";
var service = new TwitterService(oauth_consumer_key, oauth_consumer_secret);
// Now we need the Token and TokenSecret
OAuthRequestToken requestToken = service.GetRequestToken("http://localhost:37808/");
string authURL = service.GetAuthorizationUri(requestToken).ToString();
Process.Start(authURL);
SendTweetOptions options = new SendTweetOptions();
options.Status = "Hello there Twitter";
service.SendTweet(options);
var re = service.Response.Response;
return View();
}
Am I doing anything wrong?
Finally solved the issue and it works well. Based upon comments from Yort.
public ActionResult AccessToken()
{
// Step 1 - Retrieve an OAuth Request Token
TwitterService service = new TwitterService(ConfigurationManager.AppSettings["TwitterConsumerKey"], ConfigurationManager.AppSettings["TwitterConsumerSecret"]);
// This is the registered callback URL
OAuthRequestToken requestToken = service.GetRequestToken("http://localhost:37808/Twitter/OToken");
// Step 2 - Redirect to the OAuth Authorization URL
Uri uri = service.GetAuthorizationUri(requestToken);
return new RedirectResult(uri.ToString(), false /*permanent*/);
//return View();
}
public ActionResult OToken()
{
return View();
}
public ActionResult UserInfo(string oauth_token, string oauth_verifier)
{
var requestToken = new OAuthRequestToken { Token = oauth_token };
// Step 3 - Exchange the Request Token for an Access Token
TwitterService service = new TwitterService(ConfigurationManager.AppSettings["TwitterConsumerKey"],
ConfigurationManager.AppSettings["TwitterConsumerSecret"]);
OAuthAccessToken accessToken = service.GetAccessToken(requestToken, oauth_verifier);
// Step 4 - User authenticates using the Access Token
service.AuthenticateWith(accessToken.Token, accessToken.TokenSecret);
TwitterUser user = service.VerifyCredentials(new VerifyCredentialsOptions());
ViewBag.Message = string.Format("{0}", user.ScreenName);
// Step 5 - Send Tweet to User TimeLine
SendTweetOptions options = new SendTweetOptions();
string URL = "file:\\C:\\Users\\<User>\\Desktop\\test.jpg";
string path = new Uri(URL).LocalPath;
// Sending with Media
using (var stream = new FileStream(path, FileMode.Open))
{
service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = "<status>",
Images = new Dictionary<string, Stream> { { path, stream } }
});
}
var responseText = service.Response.StatusCode;
if (responseText.ToString() == "OK")
{
ViewBag.Message = "Tweet Successful";
}
else
{
ViewBag.Message = "Tweet Unsuccessful";
}
return View();
}
}
I don't believe you can send Tweets as just a consumer, the Tweets have to be "owned" by a user account. You need to register a Twitter account, then do the full oauth authentication process to get an access token (in addition to the consumer token), then reauthorise the TweetSharp service using both tokens.
Your code above nearly gets there (I think). After the Process.start call there needs to be logic to use the verifier returned in the browser (a number displayed after the user logs in) to complete the auth process and act as that user. At the moment, your code gets half way through that process but does not complete it, so when you try to tweet your TweetSharp service is only authed as the app and not the user.
The originalTweetSharp readme.md does include the missing bits of code. Step 3 needs the actual verifier returned in the browser after login:
// Step 3 - Exchange the Request Token for an Access Token
string verifier = "123456"; // <-- This is input into your application by your user
OAuthAccessToken access = service.GetAccessToken(requestToken, verifier);
// Step 4 - User authenticates using the Access Token
service.AuthenticateWith(access.Token, access.TokenSecret);
//Now your tweet call should work here.
It also looks like you're doing this in a web app on the server? In which case you're using entirely the wrong oauth flow (I believe). This one is designed for desktop apps, hence the call that starts a new browser process for the user to login with. I'm not entirely sure how the web flow works as I've never used it, but I believe you need to redirect the user to the authorisation url you receive, and the callback registered with Twitter should point back to your site. I think there is some kind of state parameter that can be passed back through the oauth flow so you can implement your own logic to pickup where you left off based on a session id or similar.
I worked on this subject before. You have to developer account before the send tweet because you need tokens and keys. It's my windows service project.
I wrote my tokens and key codes in App.config
<appSettings>
<add key="twitterAccessToken" value="*****"/>
<add key="twitterAccessTokenSecret" value="*****"/>
<add key="twitterConsumerKey" value="*****"/>
<add key="twitterConsumerSecret" value="*****"/>
public static void SendTweet()
{
try
{
GetPixelImageFile();
string key = ConfigurationSettings.AppSettings.Get("twitterConsumerKey");
string secret = ConfigurationSettings.AppSettings.Get("twitterConsumerSecret");
string token = ConfigurationSettings.AppSettings.Get("twitterAccessToken");
string tokenSecret = ConfigurationSettings.AppSettings.Get("twitterAccessTokenSecret");
string message = "Color, Colorful, Pixel, Art, PixelColouring, Follow";
var service = new TweetSharp.TwitterService(key, secret);
service.AuthenticateWith(token, tokenSecret);
using (var stream = new FileStream(#"C:\Images\Pixel.png", FileMode.Open))
{
var result = service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = message,
Images = new Dictionary<string, Stream> { { "john", stream } }
});
SendMail("SendTweet", (result == null ? "" : result.Text));
}
}
catch (Exception ex)
{
SendMail("SendTweet", ex.Message);
}
}
Ok so I'm breaking my head in half for trying to figure out what's wrong.
My fb app has been granted the publish_actions permission, I followed up all the Review Guidelines
It is also live(public) and with the green circle (meaning it is all ok). See the image
But... my iOS app (Using Fb Unity SDK) says: "This doesn't let the app post to Facebook" and as of today it doesn't list the permission I have been granted on 09/June/2016
Obviously I can't post anything (mostly photos/videos) from my app...
Here's the code (C#) that I use to init Fb.
public void CallFBLogin()
{
var param = new List<string>(){"public_profile", "email", "user_friends", "publish_actions"};
FB.LogInWithPublishPermissions(param, AuthCallback);
}
private void AuthCallback(ILoginResult result){
if(FB.IsLoggedIn){
//Get Access Token
var aToken = Facebook.Unity.AccessToken.CurrentAccessToken;
Debug.Log("ACCESS TOKEN GRANTED");
PlayerPrefs.SetInt("FBAuth", 1);
//Print current access token's granted permissions
foreach(string perm in aToken.Permissions){
Debug.Log("PERMISSION GRANTED: "+perm);
}
}else{
PlayerPrefs.SetInt("FBAuth", 0);
Debug.Log("USER CANCELLED LOGIN");
}
}
Here's the code (C#) that I use to post to Facebook. It works perfectly fine
IEnumerator UploadVideoToFB(){
yield return new WaitForEndOfFrame();
//Post to FB Graph API: Video
//string host = "https://graph-video.facebook.com/v2.6/";
string uri = "me/videos";
string videoUrl = mainReviewVideo.m_strFileName;
String videoUrlIOS = videoUrl.Replace (" ","%20");
WWW www = new WWW(videoUrlIOS);
while(!www.isDone){
yield return null;
Debug.Log("Progress;" + www.progress);
}
//CREATE WWW FORM TO MAKE A POST REQUEST
var form = new WWWForm();
//ADD THE VIDEO DATA AS BYTES
form.AddBinaryData("file", www.bytes, "Video.mov");
//MAKE THE POST REQUEST, CALLBACK IS UploadVideoFinish
FB.API(uri, HttpMethod.POST, UploadVideoFinish, form);
}
private void UploadVideoFinish(IGraphResult result){
var res = JSONNode.Parse(result.ToString());
string fbVideoID = res["id"];
}
What am I doing wrong? Why can't I publish something to Fb through my app?
UPDATE
So turns out that the workflow for publish_actions is:
Login (public_profile, email, user_friends), use:
var params = new List<string>(){"public_profile", "email", "user_friends", "publish_actions"};
FB.LoginWithReadPermissions(params, AuthCallback);
Whenever you are ready to publish something, trigger:
var params = new List<string>(){"publish_actions"}
FB.LoginWithPublishPermissions(params,AuthCallback);
That way you let your users decide when and who to publish.
I've some difficulty providing a login form for authentication with onedrive.
The scenario: a Windows 7 software is made to retrieve and upload some data, a user should login into onedrive (personal onedrive) to achieve this.
According to this doc (http://msdn.microsoft.com/en-US/library/dn631823.aspx)
I should write:
var authClient = new LiveAuthClient();
LiveLoginResult result = await authClient.LoginAsync("wl.signin", "wl.skydrive");
if (result.Status == LiveConnectSessionStatus.Connected)
{
connected = true;
var connectClient = new LiveConnectClient(result.Session);
var meResult = await connectClient.GetAsync("me");
dynamic meData = meResult.Result;
updateUI(meData);
}
}
In my version (the last one) of live sdk I must optain an API key:
var _authClient = new LiveAuthClient("000xxxxxxxxxxxxxxxx"); //LiveAuthClient() simply not exist
var scopes = new string[] { "wl.signin", "wl.skydrive" }; // "wl.skydrive_update"
LiveLoginResult result = await _authClient.InitializeAsync(scopes);
if (result.Status == LiveConnectSessionStatus.Connected)
{
Debug.WriteLine("Connected");
}
The problem is that I can't find LoginAsync method and why must I obtain an API key? I'm a bit confused. Thanks.
You should see a "GetLoginUrl" method that you can use to render the login page for the user. Here's a link to a sample application that shows you how this can be accomplished:
https://github.com/liveservices/LiveSDK-for-Windows/tree/master/src/Desktop/Samples/ApiExplorer
Try reading this doc on Desktop apps: http://msdn.microsoft.com/en-us/library/dn631817.aspx
It shows a different way to provide login on desktop.