I am using DotNetOpenAuth Package,
I am trying to upload a package to google docs,
Using client credentials i am able to do it successfully using
following code,
DocumentEntry objDocumentEntry = new DocumentEntry();
objDocumentsService.setUserCredentials(strUserName,strPassWord);
string strAuthenticationToken =
objDocumentsService.QueryAuthenticationToken();
objDocumentEntry =
objDocumentsService.UploadDocument(Server.MapPath("test.docx"), "New
Name");
I want achieve save with plain oAuth,
I am having following code written for it,
if (this.TokenManager != null)
{
if (!IsPostBack)
{
var google = new
WebConsumer(GoogleConsumer.ServiceDescription, this.TokenManager);
// Is Google calling back with authorization?
var accessTokenResponse =
google.ProcessUserAuthorization();
if (accessTokenResponse != null)
{
this.AccessToken =
accessTokenResponse.AccessToken;
}
else if (this.AccessToken == null)
{
// If we don't yet have access, immediately
request it.
GoogleConsumer.RequestAuthorization(google,
GoogleConsumer.Applications.DocumentsList);
}
}
}
I successfully get "AccessToken",
But i am not sure how to use it..
Do we need to exchange this token? what excatly to do with this token?
Is it a sessionToken?
Please provide some inputs, I am badly stuck with this problem from
last 3 days,
Prashant C
Related
I want to authorize an OAuth JSON Web Token granted by Azure Active Directory, and one thing I need to do is get more information about the application in the token's appId using the Microsoft Graph API.
Microsoft Graph API allows me to GET an app by its id via
https://graph.microsoft.com/beta/applications/{id}
, but NOT by its appId via
https://graph.microsoft.com/beta/applications/{appId}
The best way I see to use Microsoft Graph API to GET an app using its AppId is via a filter like so:
https://graph.microsoft.com/beta/applications?filter=appId eq '{appId}'
The above filter works just fine in the Microsoft Graph Explorer, but when calling the Graph API using a GET request using HttpUrlConnection, my request fails with HTTP Code 400 and message "Bad Request".
It's weird because using the exact same HttpUrlConnection to GET the full range of applications via
https://graph.microsoft.com/beta/applications
works just fine.
Is there something about the filter functionality that I can't use it in a Microsoft Graph API GET request? How should I get info on an app by its AppId?
Here is a snippet of the Java code I am using for my HttpURLConnection:
url = new URL(String.format("https://graph.microsoft.com/beta/applications?filter=appId eq '%s'", appId));
final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Authorization", "Bearer " + result.getAccessToken());
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("Content-Type", "application/json");
final int httpResponseCode = conn.getResponseCode();
if (httpResponseCode == 200 || httpResponseCode == 201) {
BufferedReader in = null;
final StringBuilder response;
try {
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String inputLine;
response = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
} finally {
in.close();
}
final JSONObject json = new JSONObject(response.toString());
return json.toString(4);
} else {
return String.format("Connection returned HTTP code: %s with message: %s",
httpResponseCode, conn.getResponseMessage());
}
In case someone else comes looking for this, if you are using the GraphServiceClient you can do this:
var appId = "some app id";
var response = await _graphClient.Applications
.Request()
.Filter($"appId eq '{appId}'")
.GetAsync();
var azureAddApplication = response.FirstOrDefault() ?? throw new ArgumentException($"Couldn't find App registration with app id {appId}");
In case someone is searching this... the API call should be done with the app's Object ID, not the app ID.
You should URLEncode the query parameters.
String url2=URLEncoder.encode("$filter=appId eq '{applicationId}'");
URL url = new URL("https://graph.microsoft.com/beta/applications?"+url2);
I'm trying to implement google login in my app using xamarin.auth like below
var auth = new OAuth2Authenticator("284202576320-7kgdhaa5sgvkoe03jmmcv0p8lfdma306.apps.googleusercontent.com","cAZW7uegD-h2-
tNMMf5q1UGQ","https://www.googleapis.com/auth/userinfo.email",new
Uri("https://accounts.google.com/o/oauth2/auth"),new
Uri("http://dev.myfav.restaurant/Account/LoginComplete"),new
Uri("https://accounts.google.com/o/oauth2/token"),null,true)
{
AllowCancel = true,
};
but Completed event not firing and its going to web page after login :(
I'm getting below error
i need to get back user to my app how can i achieve this ???? Can anyone help me on this please.
Thanks in advance
Hey follow these two examples one is using web view and one is using google sign in sdk for google auth.
https://timothelariviere.com/2017/09/01/authenticate-users-through-google-with-xamarin-auth/
and
https://developer.xamarin.com/samples/xamarin-forms/WebServices/OAuthNativeFlow/
So according to this issue reported by Mounika.Kola .I think u should refer that authenticator.Completed -= OnAuthCompleted is there in ur code. For reference just see these codes which i used for google authorization in Xamarin Forms.
void OnLoginClicked(object sender, EventArgs e)
{
string clientId = null;
string redirectUri = null;
switch (Device.RuntimePlatform)
{
case Device.iOS:
clientId = Constants.iOSClientId;
redirectUri = Constants.iOSRedirectUrl;
break;
case Device.Android:
clientId = Constants.AndroidClientId;
redirectUri = Constants.AndroidRedirectUrl;
break;
}
var authenticator = new OAuth2Authenticator(
clientId,
null,
Constants.Scope,
new Uri(Constants.AuthorizeUrl),
new Uri(redirectUri),
new Uri(Constants.AccessTokenUrl),
null,
true);
authenticator.Completed += OnAuthCompleted;
authenticator.Error += OnAuthError;
AuthenticationState.Authenticator = authenticator;
var presenter = new Xamarin.Auth.Presenters.OAuthLoginPresenter();
presenter.Login(authenticator);
}
async void OnAuthCompleted(object sender, AuthenticatorCompletedEventArgs e)
{
var authenticator = sender as OAuth2Authenticator;
if (authenticator != null)
{
authenticator.Completed -= OnAuthCompleted;
authenticator.Error -= OnAuthError;
}
User user = null;
if (e.IsAuthenticated)
{
// If the user is authenticated, request their basic user data from Google
// UserInfoUrl = https://www.googleapis.com/oauth2/v2/userinfo
var request = new OAuth2Request("GET", new Uri(Constants.UserInfoUrl), null, e.Account);
var response = await request.GetResponseAsync();
if (response != null)
{
// Deserialize the data and store it in the account store
// The users email address will be used to identify data in SimpleDB
string userJson = await response.GetResponseTextAsync();
user = JsonConvert.DeserializeObject<User>(userJson);
}
if (account != null)
{
store.Delete(account, Constants.AppName);
}
await store.SaveAsync(account = e.Account, Constants.AppName);
await DisplayAlert("Email address", user.Email, "OK");
}
}
I hope it helps you.
In iOS once you have completed the authentication with Xamarin.Auth you just need to dismiss the viewController and you will be put back in your app.
You do this subscribing to the Completed event of the OAuth2Authenticator
auth.Completed += (sender, e) =>
{
DismissViewController(true, null);
};
If the "Native UI" is used (the last parameter in the constructor is set to true), which means that external/system browser is used for login not WebView. So, on Android instead of WebView [Chrome] CustomTabs is used and on iOS instead of UIWebView (or WKWebView) SFSafariViewController is used.
With native UI user is leaving your app and the only way to return to your app is app-linking (or deep-linking) and this requires completely different approach.
1st you cannot use http[s] scheme for redirect_url (OK on Android it is possible, but on iOS not). Use custom scheme for that.
See the sample[s] (Xamarin.Forms ComicBook):
https://github.com/moljac/Xamarin.Auth.Samples.NugetReferences
And the docs in the repo:
https://github.com/xamarin/Xamarin.Auth/tree/master/docs
I have a .NET Web API that I am using to do some interaction with Microsoft Graph and Azure AD. However, when I attempt to create an extension on the user, it comes back with Access Denied.
I know it is possible from the documentation here however, it doesnt seem to work for me.
For the API, I am using client credentials. So my web app authenticates to the API using user credentials, and then from the API to the graph it uses the client.
My app on Azure AD has the Application Permission Read and Write Directory Data set to true as it states it needs to be in the documentation for a user extension.
I know my token is valid as I can retrieve data with it.
Here is my code for retrieving it:
private const string _createApprovalUrl = "https://graph.microsoft.com/beta/users/{0}/extensions";
public static async Task<bool> CreateApprovalSystemSchema(string userId)
{
using(var client = new HttpClient())
{
using(var req = new HttpRequestMessage(HttpMethod.Post, _createApprovalUrl))
{
var token = await GetToken();
req.Headers.Add("Authorization", string.Format("Bearer {0}", token));
req.Headers.TryAddWithoutValidation("Content-Type", "application/json");
var requestContent = JsonConvert.SerializeObject(new { extensionName = "<name>", id = "<id>", approvalLimit = "0" });
req.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
using(var response = await client.SendAsync(req))
{
var content = await response.Content.ReadAsStringAsync();
ApprovalSystemSchema schema = JsonConvert.DeserializeObject<ApprovalSystemSchema>(content);
if(schema.Id == null)
{
return false;
}
return true;
}
}
}
}
Is there anyone who may have a workaround on this, or information as to when this will be doable?
Thanks,
We took a look and it looks like you have a bug/line of code missing. You appear to be making this exact request:
POST https://graph.microsoft.com/beta/users/{0}/extensions
Looks like you are missing the code to replace the {0} with an actual user id. Please make the fix and let us know if you are now able to create an extension on the user.
I am building a Universal Windows Platform (UWP) app that uses the Azure App Service Mobile App backend as well as the user's OneDrive account. I have 2 requirements for authentication:
If the user is logged in to their UWP device with a Microsoft account (e.g. Windows 10) then I don't want them to be presented with a login prompt (i.e. Single Sign On, re-using their Microsoft account credentials).
I want to have a single authentication event across Azure & OneDrive, i.e. the user authorises once and I re-use that token for both services.
I did this in Windows Phone 8 with an Azure Mobile Service by logging in with the Live SDK and then passing the returned token to the MobileServiceClient.LoginAsync() method, however I can't get this to work in UWP with an Azure Mobile App. When I call that same method I receive a 401 Unauthorised response.
I have associated my UWP app with the store and set up the
application at the Microsoft Account Developer Centre, including
adding the redirect URI from the Azure Mobile App.
I have set up the Azure App Service Mobile App, including adding the
Client ID & Secret from the Microsoft Account Developer Centre.
I have tried numerous ways to retrieve the token, including the
OnlineIdAuthenticator, WebAuthenticationCoreManager and
WebAuthenticationBroker. None has worked so far.
I currently use the following code in a class LiveAuthenticationService to retrieve an access token:
public async Task<bool> LoginAsync()
{
AccessToken = null;
bool success = false;
OnlineIdAuthenticator onlineIdAuthenticator = new OnlineIdAuthenticator();
EventWaitHandle waithandle = new ManualResetEvent(false);
OnlineIdServiceTicketRequest serviceTicketRequest = new OnlineIdServiceTicketRequest(scopes, "DELEGATION");
UserIdentity result = await onlineIdAuthenticator.AuthenticateUserAsync(serviceTicketRequest);
if (!string.IsNullOrWhiteSpace(result?.Tickets[0]?.Value))
{
currentUserId = result.SafeCustomerId;
AccessToken = result.Tickets[0].Value;
success = true;
waithandle.Set();
}
else
{
await logger.LogErrorAsync("Error signing in to Microsoft Live",
new Dictionary<string, string> { { "errorCode", result?.Tickets[0]?.ErrorCode.ToString() } });
}
waithandle.WaitOne(10000); //10 second timeout
return success;
}
And then this to attempt to login to my Azure Mobile App with that token, which uses LiveAuthenticationService from above:
private async Task RefreshUserIdAndAccessToken()
{
try
{
var tcs = new TaskCompletionSource<MobileServiceUser>();
var authService = new LiveAuthenticationService();
await UiDispatcher.RunAsync(CoreDispatcherPriority.Normal,
async () =>
{
try
{
await authService.LoginAsync();
var jsonAuthenticationToken = JObject.Parse(#"{""authenticationToken"": """ + authService.AccessToken + #"""}");
tcs.SetResult(await mobileService.LoginAsync(MobileServiceAuthenticationProvider.MicrosoftAccount, jsonAuthenticationToken));
}
catch (Exception ex)
{
tcs.SetException(ex);
}
});
var user = await tcs.Task;
currentUserId = user.UserId;
AccessToken = user.MobileServiceAuthenticationToken;
}
catch (Exception ex)
{
await logger.LogExceptionAsync(ex,
Constants.LOGGING_DATAKEY_REFRESHACCESSTOKENFAILURE,
currentUserId);
currentUserId = null;
AccessToken = null;
}
}
As stated this results in a 401 Unauthorised response from Azure. I have run Fiddler and the request seems to be correct, the expected authentication token is included in a JSON payload with the request.
UPDATE
One thing I can see is that the token issued by the code above is almost 900 characters long, all in the form YnElFkAAcK8bRSQab/FK+PT5n/wA4CPU..., while the token issued if I let Azure Mobile App handle the authentication, i.e. call MobileServiceClient.LoginAsync() without passing a token, is only about 350 characters long and in the form hbGciOi.eyJmdWWxsIiwiRGJn... (notice the period towards the beginning).
This issue is really causing me problems now. I can't release the app without the authentication working and I can't figure out how to fix it. Any help will be appreciated.
This was a tough one for me to solve as I was facing this problem too.
The most important part is the OnlineIdServiceTicketRequest the request should look like this:
var mobileServicesTicket = new OnlineIdServiceTicketRequest("https://yourmobileservice.azure-mobile.net/", "JWT");
Note that we are specifying your endpoint and also requesting a JWT token instead of delegation. This will get the 350ish character token you were looking for.
Here is a full code sample of what I'm doing:
public async Task<bool> LoginAsync()
{
var authenticator = new Windows.Security.Authentication.OnlineId.OnlineIdAuthenticator();
var mobileServicesTicket = new Windows.Security.Authentication.OnlineId.OnlineIdServiceTicketRequest("https://yourendpoint.azure-mobile.net/", "JWT");
var ticketRequests = new List<OnlineIdServiceTicketRequest>() { mobileServicesTicket };
var authResult = await authenticator.AuthenticateUserAsync(ticketRequests, CredentialPromptType.PromptIfNeeded);
if ((authResult.Tickets.Count == 1) && (authResult.Tickets[0].ErrorCode == 0))
{
var accessToken = authResult.Tickets[0];
var res = await _mobileServiceClient.LoginWithMicrosoftAccountAsync(accessToken.Value);
return true;
}
else
{
return false;
}
}
_mobileServiceClient is injected into the class and is a reference to Microsoft.WindowsAzure.MobileServices.MobileServiceClient object within the WindowsAzure.MobileServices library.
I actually ended up writing a blog article about this problem here http://jshapland.com/single-sign-on-with-azure-mobile-services-in-a-uwp-app/
UPDATE: PLEASE SEE THIS POST: https://stackoverflow.com/a/20379623/687549
Been reading I think almost all questions on SO about external providers and how to get extra info/data/metadata/claims/orwhateveryouwannacallit in particular the email address which many use as the username on modern websites.
So the problem that I was facing was that I wanted to retrieve the email from the Facebook provider with as little code as possible. I thought to myself; the new ASP.NET Identity framework must have this buil-in and can do this with probably just a couple of lines of code. I searched and all I could find was these imensely large chunks of code and I thought to myself: there has got to be another more simpler way. And here it is, as an answer in this questionthread.
I managed to get this working with both Facebook and Google but what I'm concerned about is wheather or not I'm doing this right without any consequenses somewhere else in the code.
For instance: Do you really only need to specify the Scopes.Add("email") for it all to work or why haven't I been able to find more info about this on the interweb?
UPDATE: PLEASE SEE THIS POST: https://stackoverflow.com/a/20379623/687549
Startup.Auth.cs:
var facebookAuthenticationOptions = new FacebookAuthenticationOptions()
{
AppId = "myAppId",
AppSecret = "myAppSecret"
};
facebookAuthenticationOptions.Scope.Add("email");
app.UseFacebookAuthentication(facebookAuthenticationOptions);
AccountController (default mvc 5 template app stuff)
//
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// These next three lines is how I get the email from the stuff that gets returned from the Facebook external provider
var externalIdentity = HttpContext.GetOwinContext().Authentication.GetExternalIdentityAsync(DefaultAuthenticationTypes.ExternalCookie);
var emailClaim = externalIdentity.Result.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email);
var email = emailClaim.Value;
// Sign in the user with this external login provider if the user already has a login
var user = await UserManager.FindAsync(loginInfo.Login);
if (user != null)
{
await SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
else
{
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
// Populate the viewmodel with the email
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { UserName = email });
}
}
I have the same problem. You need to edit and add this code to ExternalLoginCallback in the AccountController
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// added the following lines
if (loginInfo.Login.LoginProvider == "Facebook")
{
var identity = AuthenticationManager.GetExternalIdentity(DefaultAuthenticationTypes.ExternalCookie);
var access_token = identity.FindFirstValue("FacebookAccessToken");
var fb = new FacebookClient(access_token);
dynamic myInfo = fb.Get("/me?fields=email"); // specify the email field
loginInfo.Email = myInfo.email;
}
Note the code dynamic myInfo = fb.Get("/me?fields=email"); this will work for facebook app with version 2.4, but for old version you can write this
dynamic myInfo = fb.Get("email");