Accessing the Microsoft Graph after OpenId Connect Azure AD Callback - asp.net

Fundamentally all I need to do is grab a users profile photo after successful login (asp.net 4.8) since it doesn't seem that I can request the photo to come over with the login claims.
This is the callback handler
SecurityTokenValidatedNotification<Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification
This is how I get the Identity from that callback and it's all there looking good
var identity = notification.AuthenticationTicket.Identity;
So I'm trying to callback with RestSharp
var client = new RestSharp.RestClient("https://graph.microsoft.com");
var request = new RestSharp.RestRequest($"/v1.0/users/{email}/photo/$value", RestSharp.Method.GET);
var callbackResult = client.Execute(request);
Debugger.Break();
if (callbackResult.StatusCode == HttpStatusCode.OK)
{
Debugger.Break();
}
But it keeps (I suppose OBVIOUSLY) coming back as unauthorized. Is there some token or something I can use now that the user has authenticated to add a header or querystring or something that will just get me the extra data easily?

Related

Firebase Rest Api setting language for user or app?

Firebase has option to set language code or app language for current user in order to get verification, password reset emails in defined language like below. below is from Android SDK implementation
Additionally you can localize the verification email by updating the
language code on the Auth instance before sending the email. For
example:
auth.setLanguageCode("fr"); // To apply the default app language
instead of explicitly setting it. // auth.useAppLanguage();
But i am using rest api within my uwp application and this option is not defined in rest api documentation
Does anybody know how to achieve this?
Anybody else is looking for solution. you need to add header as X-Firebase-Locale: 'fr'. C# code will look like as below. you can find the full implementation here
public async Task SendEmailVerificationAsync(string firebaseToken, string locale = null)
{
var content = $"{{\"requestType\":\"VERIFY_EMAIL\",\"idToken\":\"{firebaseToken}\"}}";
var StringContent = new StringContent(content, Encoding.UTF8, "application/json");
if (locale != null)
StringContent.Headers.Add("X-Firebase-Locale", locale);
var response = await this.client.PostAsync(new Uri(string.Format(GoogleGetConfirmationCodeUrl, this.authConfig.ApiKey)), StringContent).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
}

GA Enhanced Ecommerce Missing Purchase Events

We are sending the purchase events from the server with code like this:
using (var httpClient = new RestClient())
{
httpClient.SendAsync(new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
});
}
But around 15-20% of the events never gets registered in GA.
Google always seem to respond with a GIF and status code 200, so it is hard to tell which events are not processed successfully.
In the beginning we were using the javascript API to send the event, but when we switched to server side, we copied the request it was creating and tried to replicate it with HttpClient.
The request send looks like the following:
https://www.google-analytics.com/collect?v=1&_v=j47&a=817546713&t=event&ni=0&_s=1&
dl=#scheme + host + pathAndQuery#&dp=#path#&dt=#path#&ul=#browser language#&de=#browser encoding#&sd=#bit#&sr=#screen resolution#&vp=#viewable browser area#&cid=#Id taken from the _ga cookie#&je=0&fl=24.0%20r0&ec=Ecommerce&ea=purchase &_u=SCEAAAALI20%25~&jid=&tid=#TrackingId#&gtm=#TagManagerId#&ti=#OrderId#&ta=&
tr=#TotalPrice#&tt=#TotalTax#&ts=#ShippingPrice#&tcc=#VoucherCode# &pa=purchase&cu=#CurrencyCode#&pr1nm=#ProducteName#&pr1id=#ProductId#&pr1pr=#ProductPrice#&pr1br=#Brand#&pr1ca=&pr1va=#Variant#&pr1qt=#Quantity#&z=#Randomly generated unique id#
Any ideas about what is wrong or how to debug it is welcome
You shouldn't do that on the backend. The correct way is to do that on the frontend
The easiest and the correct way is to send data to your dataLayer and then in GTM send an event to GA.
P.S. In your C# code I can see the problem that you are not awaiting async method. If your method is not async, then you can use it like that:
var temp = httpClient.SendAsync(new HttpRequestMessage
{
RequestUri = new Uri(url),
Method = HttpMethod.Get
}).Result;

Does the Facebook C# SDK depend on cookies on the server?

I'm using the Facebook C# SDK and am trying to figure out exactly how it works. I actually use an AJAX web method to lookup the Facebook account details based on the authenticated user ID, which looks something like this:
if (response.status === "connected")
{
KitchenPC.LogonFB(response.authResponse.userID, checkResult, facebookError);
}
On the server side, the LogonFB web method does something like:
Client = new FacebookClient(applicationId, applicationSecret);
var result = Client.Get(path) as IDictionary<string, object>;
UserId = Int64.Parse((String)result["id"]);
Name = result["name"] as String;
FirstName = result["first_name"] as String;
LastName = result["last_name"] as String;
Location = result.ContainsKey("location") ? result["location"] as String : "";
Gender = result.ContainsKey("gender") ? result["gender"] as String : "";
Email = result["email"] as String;
Where path is the user ID passed in from the client.
My Question:
I'm switching from ASP.NET Web Service to WCF, and WCF does not support cookies. In fact, HttpContext.Current will be null within the WCF pipeline. I was under the impression that the Facebook C# SDK depended on the fbm_ and fmsr_ cookies being passed in on the request, which would be used to validate the session with the Facebook server. However, much to my surprise, the .Get() call still works, and user information is returned. I also dug through the SDK source code and nowhere in it do I find references to HttpContext.Current.
Does the Facebook C# SDK work completely independently of cookies? Does this mean that all I need is the user's Facebook ID, and as long as they've previously approved my app ID, I can grab information about their account?
I just want to make sure I'm not doing anything wrong, and I'm not going to run into trouble in production.
When you pass the constructor with appId and appSecret, it will auto set the access token as app access token using string.Concat(appId, '|', appSecret). That constructor has been removed in newer version of the sdk. https://github.com/facebook-csharp-sdk/facebook-csharp-sdk/issues/103
Set it to null if you don't want the access token.
Client = new FacebookClient(applicationId, applicationSecret);
Client.AccessToken = null;
var result = Client.Get(path) as IDictionary<string, object>;

Graph api, C# to share data from app to my wall

i am trying to develop an app which can allow me to share data on Facebook wall.
For eg: consider the Facebook Canvasapp "Run with Friends". This is a canvas app using Python and Php.
https://developers.facebook.com/docs/samples/. I will be able to share data from this app to my wall./me
Before doing this v need a access token. I was able to get the authorization, accesstoken using Graph api, Oauth2.0, C#, asp.net
public string AuthorizationLinkGet(bool bUserInfo, bool bFriends, bool bfeed, bool bPhotos, bool bEvents, bool bMessages)
{
string url = string.Format("{0}?client_id={1}&redirect_uri={2}", AUTHORIZE, this.ConsumerKey, CALLBACK_URL);
if (bUserInfo == true || bFriends == true || bfeed == true || bEvents == true || bPhotos == true || bMessages == true)
{
url += "&scope=email";
if (bUserInfo == true)
{
url += ",user_about_me,user_interests,user_likes,user_location,user_notes,user_education_history,user_hometown";
}
if (bFriends == true)
{
url += ",read_friendlists,user_groups";
}
if (bfeed == true)
{
url += ",read_stream";
}
if (bEvents == true)
{
url += ",user_events";
}
if (bEvents == true)
{
url += ",user_photo_video_tags";
}
if (bMessages == true)
{
url += ",read_mailbox";
}
}
return url;
}
<add key="APIKey" value="*************************"/>
<add key="Secret" value="**********************"/>
So now how do I be able to share data from the app onto my FB wall.
I've tried Sharekit but look like Sharekit is for mobile apps.
public void AccessTokenGet(string authToken)
{
this.Token = authToken;
string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
ACCESS_TOKEN, this.ConsumerKey, CALLBACK_URL, this.ConsumerSecret, authToken);
string response = WebRequest(Method.GET, accessTokenUrl, String.Empty);
if (response.Length > 0)
{
//Store the returned access_token
NameValueCollection qs = HttpUtility.ParseQueryString(response);
if (qs["access_token"] != null)
{
this.Token = qs["access_token"];
}
}
}
does any one know how to develop this canvas app in C# using Graph Api
I have no idea abt all the curls and things in Php
Also, I see people using REST, facebookservice, facebook SDK. Where would these fit it?
Thanks
Sun
Ask for the publish stream permission.
You need to POST to https://graph.facebook.com/USER_ID/feed/access_token=lerolero, posting a json like this:
{"name": "name"
"link": "http://www.link.com/",
"caption": "title",
"description": "description",
"picture": "http://www.link.com/image.jpg"}
http://developers.facebook.com/docs/reference/api/, read the publishing section, you can send a lot of other information.
Edit:
I see two possibilities.
If the facebook integration its not part of your bussiness rules (if you will not use the user information), you can just add the SHARE widget, in this case, the user will se a button, and when he click the button, the facebook authentication page will open, and when the authentication is done, the share widget will popup automatically.
If you gonna access the user information (if will be somehow attached to the user account), then, when the user clicks the button, you have to check the user account forward a facebook account, if theres not one, you have to open a authentication popup, if the user succeeds to login into facebook, the authentication popup will return you a verification code. You must exchange the verication code for a access token and attach the access token to the user account in your database. In the authentication step, you have to ask for two special permissions, the stream publish permission and the offline access permission. The first one is about the resource to publish in the user wall, and the second one its about the access token life cycle (if you dont ask for this permission, the access token will have a short life cycle, and you will need to reauthenticate the user into facebook again and again, we dont want that).
Into the code:
When the user clicks a button, call a ajax function that checks if there's a access token in the user account. If theres, return the access token (take care here, if you create a ajax that return a access tokem based on a user id, you will have a very bad security issue), if theres not, return false.
If the code returned is false, call a function that opens a popup with the facebook authentication url. In the facebook authentication popup callback url, just exchange the verification code for a access token and store it in the database. You need to keep listening the popup.closed state, to know when the process is done and call another ajax function that checks if now theres a access token in the user account or not, if not, the user just closed the popup.
If the code returned is an access token, call a ajax function that post in the user wall, its very easy, like this:
string facebookurl = "https://graph.facebook.com/me/feed?access_token=32423"
string parameters = "message=aaaa&link=bbbb";
WebRequest req = WebRequest.Create(facebookurl);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(parameters);
req.ContentLength = bytes.Length;
Stream stream = req.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
stream.Close();
WebResponse res = req.GetResponse();
StreamReader streamReader = new StreamReader(res.GetResponseStream());
If you need any other piece of code, let me know.

RIA Services, Forms Authentication and extra cookies

I have an Silverlight 4 RIA Services application with custom Forms Authentication. The custom authentication service works like a charm.
The problems is I want to serialize the user object in a cookie which is then sent with each subsequent request.
I create the cookie and add it to the response cookie collection but on the next request the only cookies in the cookie collection are ASPXAUT and ASPX_SESSIONId, of the custom cookie not a trace.
This is the cookie management class:
public class CookieManager:ISessionManager
{
public object this[string key]
{
get
{
var context = getCurrentContext();
var cookie = context.Request.Cookies[key];
if (cookie == null) return null;
return deserialize(cookie.Value);
}
set
{
var context = getCurrentContext();
string cookieValue = serialize(value);
HttpCookie cookie = new HttpCookie(key, cookieValue);
cookie.Expires = DateTime.Now.AddDays(10000);
cookie.HttpOnly = false;
context.Response.Cookies.Remove(key);
context.Response.Cookies.Add(cookie);
}
}
public void Abandon()
{
var context = getCurrentContext();
context.Response.Cookies.Clear();
}
public void Clear()
{
Abandon();
}
private HttpContext getCurrentContext()
{
return HttpContext.Current;
}
private string serialize(object value)
{
MemoryStream stream = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Context = new StreamingContext(StreamingContextStates.Clone);
formatter.Serialize(stream, value);
StreamReader reader = new StreamReader(stream);
stream.Position = 0;
string result = reader.ReadToEnd();
reader.Close();
stream.Close();
return HttpUtility.UrlEncodeUnicode(result);
}
public object deserialize(string value)
{
value = HttpUtility.UrlDecode(value);
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(value);
BinaryFormatter formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
}
It reads and saves cookies.
Now my problem is this:
What I need to enable in silverlight or in the ASP.NET (WCF) application in order for extra cookies to be sent with each request along side the authentication cookie.
EDIT:
I've inspected the HTTP request/response stack and those extra cookies are sent from the server with the WCF RIA Services response but not returned by the next service call from the client.
If I understand your edit above correctly, you've already inspected the HTTP requests and found the desired cookie present in the HTTP Set-Cookie header of the response, but missing in the Cookie header of the next request. Is this correct? If not, please clarify.
If so, the problem sounds like one of three things:
the client is not successfully saving the cookie, due to many possible reasons including:
cookie not properly formatted (unlikley)
cookie is too long
there's a client- or server-side policy (e.g. P3P) preventing saving persistent cookies.
The client is saving the cookie OK, but is not sending it back, even without Silverlight. This could be caused by, for example, a security issue where the hostname of the first request is different from the second.
The client is saving the cookie and can send it back over regular HTML pages, but not via HTTP requests sent by Silverlight.
To see if #1 is the problem, look (using your browser's ability to view cookies) at the cookies saved by your browser for that site. Is the expected cookie saved? If it is, then you can eliminate #1 as the problem. If it's not saved, start looking
To see if #2 is the problem, try creating a server-side page with no silverlight on it-- just a simple HTML page. When you visit that page with your browser, is the cookie sent as expected? If yes, then #2 is not your problem.
If #1 and #2 are not the problem, that leaves #3. Silverlight's HTTP handling is complicated, not least because you have to choose between having HTTP client requests handled by the browser or by Silverlight. Read the Silverlight cookies documentation carefully and see if any of the info therein will help you figure out the problem. Consider trying to use the "Client HTTP" setting, or if you're already using this, consider switching back to the "browser HTTP" setting and see if your problem goes away. Note that the Client HTTP setting apparently has a problem with losing new cookies after an HTTP redirect. See this thread for more info. There's a workaround discussed in that thread: using CookieContainer.
BTW, could you edit your question to include all the HTTP headers of the request and the subsequent request? This may help diagnosis.

Resources