Facebook OAuth issue MVC4 - c#

Annoyingly I have been trying to solve this issue for many hours, every answer is no direct solution:
{
"error": {
"message": "Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request",
"type": "OAuthException",
"code": 100
}
}
I have been banging my head against the wall!. I am using the facebook soap client for this http://pastebin.com/G7ysgbdX
This will allow us to integrate (with the user's permission) their timeline. Facebook is saying the URL's do not match. How do I test this?
This works locally but not on the server with the exact same code except http://free-rsvp.com/ instead of localhost:53111/
This is the below URL. I cannot see anything wrong!
Any advice would be appreciated.
provider_%3dFacebookPro%26_sid_%3da80359b555c54b8f8d2f4f8e803f9125&client_secret=212360b3ea6478fd0a0491e736b54256&code=AQCyTDStiB5gsQpKMx4uI1yFesVnLnWfE3u70VsB02-4HSyUCTbcf_3oHMo7QQI2as_pw1tpFONs8tClq4FxCr4AzuCMzLBsRnyOM3dcattTATdU-ahq5cjr4lPJNp2gkTrpgWUmqDEVQ8PBvYFB1LdWJpojxRIC24lv0GkQSSqdrct41UGHfDjhnPfI1mV945NgVJSfebhJP7O0GWxP9o9g_4svDCKa2LtCRbo7nDfWLeiE9fGULhmuJDjefAFZ5VMiYj8SrA4QtZXIu8jUQSQT89VYEP8PuG2hS_wMr0TL_GmcvEhNzQ8psPpPWFYhmSo">https://graph.facebook.com/oauth/access_token?client_id=523007704381837&redirect_uri=http%3a%2f%2ffree-rsvp.com%3a80%2fAccount%2fExternalLoginCallback%3fReturnUrl%3d%252FDashboard%26_provider_%3dFacebookPro%26_sid_%3da80359b555c54b8f8d2f4f8e803f9125&client_secret=212360b3ea6478fd0a0491e736b54256&code=AQCyTDStiB5gsQpKMx4uI1yFesVnLnWfE3u70VsB02-4HSyUCTbcf_3oHMo7QQI2as_pw1tpFONs8tClq4FxCr4AzuCMzLBsRnyOM3dcattTATdU-ahq5cjr4lPJNp2gkTrpgWUmqDEVQ8PBvYFB1LdWJpojxRIC24lv0GkQSSqdrct41UGHfDjhnPfI1mV945NgVJSfebhJP7O0GWxP9o9g_4svDCKa2LtCRbo7nDfWLeiE9fGULhmuJDjefAFZ5VMiYj8SrA4QtZXIu8jUQSQT89VYEP8PuG2hS_wMr0TL_GmcvEhNzQ8psPpPWFYhmSo
EDIT
The url that takes me to facebook is:
provider_%253DFacebookPro%2526_sid_%253Dbfe82f104ab34d1aa0f44c477c4d7819%26scope%3Demail%252Cuser_likes%252Cfriends_likes%252Cuser_birthday%252Cpublish_checkins%252Cpublish_stream%26client_id%3D523007704381837%26ret%3Dlogin&cancel_uri=http%3A%2F%2Ffree-rsvp.com%2FAccount%2FExternalLoginCallback%3FReturnUrl%3D%252FDashboard%26_provider_%3DFacebookPro%26_sid_%3Dbfe82f104ab34d1aa0f44c477c4d7819%26error%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%23_%3D_&display=page">https://www.facebook.com/login.php?skip_api_login=1&api_key=523007704381837&signed_next=1&next=https%3A%2F%2Fwww.facebook.com%2Fdialog%2Foauth%3Fredirect_uri%3Dhttp%253A%252F%252Ffree-rsvp.com%252FAccount%252FExternalLoginCallback%253FReturnUrl%253D%252FDashboard%2526_provider_%253DFacebookPro%2526_sid_%253Dbfe82f104ab34d1aa0f44c477c4d7819%26scope%3Demail%252Cuser_likes%252Cfriends_likes%252Cuser_birthday%252Cpublish_checkins%252Cpublish_stream%26client_id%3D523007704381837%26ret%3Dlogin&cancel_uri=http%3A%2F%2Ffree-rsvp.com%2FAccount%2FExternalLoginCallback%3FReturnUrl%3D%252FDashboard%26_provider_%3DFacebookPro%26_sid_%3Dbfe82f104ab34d1aa0f44c477c4d7819%26error%3Daccess_denied%26error_code%3D200%26error_description%3DPermissions%2Berror%26error_reason%3Duser_denied%23_%3D_&display=page

here is a piece of my server-side authentication code (MVC4 project). The part you should look at is how redirect URL is generated - identically - in both "Authorize" and "AuthorizeCallback" functions - and passed to facebook client:
[HttpPost]
public ActionResult Authorize(Guid eventId)
{
var #event = this.eventRepository.Find(eventId);
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = #event.Code });
var service = new FacebookClient();
var loginUrl = service.GetLoginUrl(new {
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
response_type = "code",
scope = "manage_pages, publish_actions, user_photos, publish_stream" // Add other permissions as needed
});
return new RedirectResult(loginUrl.AbsoluteUri, permanent: false);
}
public ActionResult AuthorizeCallback(string code, string eventCode, UserProfile userProfile)
{
var #event = this.eventRepository.Find(eventCode);
if (string.IsNullOrWhiteSpace(code) == true)
{
// means user clicked "cancel" when he was prompted to authorize the app
// todo: show some error message? or just redirect back?
return this.RedirectToAction("Event", "Dashboard", new { eventCode = #event.Code, feature = FeatureType.Update });
}
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = #event.Code });
var fb = new FacebookClient();
dynamic result = fb.Post("oauth/access_token", new
{
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
code = code
});
var accessToken = result.access_token;
// update the facebook client with the access token so
// we can make requests on behalf of the user
fb.AccessToken = accessToken;
// Get the user's information
dynamic me = fb.Get("me");
return this.RedirectToAction("Event", "Dashboard", new { eventCode = #event.Code, feature = FeatureType.Update });
}

Related

IdentityServer shows blank PostLogoutRedirectUri for Android Native App

I have created an OAuth Server using IdentityServer4 and .Net Core Signin Manager. The Login works great and returns to my app. The Logout doesn't seem to know who is logging out. The Logout Razor Page code is as follows:
public async Task<IActionResult> OnGet(string logoutId)
{
var logout = await _interaction.GetLogoutContextAsync(logoutId);
PostLogoutRedirectUri = logout?.PostLogoutRedirectUri;
AutomaticRedirectAfterSignOut = (PostLogoutRedirectUri != null);
ClientName = string.IsNullOrEmpty(logout?.ClientName) ? logout?.ClientId : logout?.ClientName;
SignOutIframeUrl = logout?.SignOutIFrameUrl;
LogoutId = logoutId;
if (User?.Identity.IsAuthenticated == true)
{
var idp = User.FindFirst(JwtClaimTypes.IdentityProvider)?.Value;
if (idp != null && idp != IdentityServer4.IdentityServerConstants.LocalIdentityProvider)
{
var providerSupportsSignout = await HttpContext.GetSchemeSupportsSignOutAsync(idp);
if (providerSupportsSignout)
{
if (LogoutId == null)
{
// if there's no current logout context, we need to create one
// this captures necessary info from the current logged in user
// before we signout and redirect away to the external IdP for signout
LogoutId = await _interaction.CreateLogoutContextAsync();
}
ExternalAuthenticationScheme = idp;
}
}
// delete local authentication cookie
await _signInManager.SignOutAsync();
// raise the logout event
await _events.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(), User.GetDisplayName()));
}
// check if we need to trigger sign-out at an upstream identity provider
if (TriggerExternalSignout)
{
// build a return URL so the upstream provider will redirect back
// to us after the user has logged out. this allows us to then
// complete our single sign-out processing.
string url = Url.Action("Logout", new { logoutId = LogoutId });
// this triggers a redirect to the external provider for sign-out
return SignOut(new AuthenticationProperties { RedirectUri = url }, ExternalAuthenticationScheme);
}
if (AutomaticRedirectAfterSignOut)
return Redirect(PostLogoutRedirectUri);
else
return Page();
}
When it gets called, there is a logoutId. It gets the context, but PostLogoutRedirectUri is blank. ClientId and ClientName are also blank, but the context has a field called ClientIds and the first entry is the correct ClientId for my app. The log shows as follows:
IdentityServer4.Validation.EndSessionRequestValidator: Information: End session request validation success
{
"SubjectId": "6841dc6c-0bd7-4f72-8f1c-f7czzzzzzzzz",
"Raw": {
"post_logout_redirect_uri": "mps.mobile.app://callback"
}
}
IdentityServer4.Hosting.IdentityServerMiddleware: Information: Invoking IdentityServer endpoint: IdentityServer4.Endpoints.EndSessionCallbackEndpoint for /connect/endsession/callback
IdentityServer4.Endpoints.EndSessionCallbackEndpoint: Information: Successful signout callback.
I am using IdentityModel for the Client App. I have the logout coded as follows:
_options = new OidcClientOptions
{
Authority = MPSOidc.Authority,
ClientId = MPSOidc.ClientID,
Scope = "openid profile myapi offline_access email",
RedirectUri = MPSOidc.RedirectUri,
PostLogoutRedirectUri = MPSOidc.RedirectUri,
ResponseMode = OidcClientOptions.AuthorizeResponseMode.Redirect,
Browser = new ChromeCustomTabsBrowser(this)
};
var oidcClient = new OidcClient(_options);
var r = new LogoutRequest();
await oidcClient.LogoutAsync(r);
It seems like the PostLogoutRedirectUri should show up here. Does anyone know a way to make this happen? If not, can the ClientId be used to get the Client information to find the PostLogoutRedirectUri there?
Thanks,
Jim
Here is what it was. When I logged out on the OidcClient, I didn't pass the ID Token. On my client Android app, I had to add the ID Token to the logout request:
var r = new LogoutRequest()
{
IdTokenHint = MPSOidc.Tokens.IdentityToken
};
That's all it took.
Cheers.

Why is Youtube's v3 api claiming my access token does not have permissions to insert live streams?

In the authorization stage of my application I'm requesting access via:
var req = new Google.Apis.Auth.OAuth2.Requests.GoogleAuthorizationCodeRequestUrl(new Uri(string.Format(Settings.Google.OAuth.Url, "auth")));
req.ClientId = Settings.Google.OAuth.ClientId;
req.ResponseType = "code";
req.Scope = "https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtubepartner";
req.RedirectUri = string.Format(Settings.Integration.HandshakeUrl, "youtube");
req.AccessType = "offline"; // required to get refreshToken.
req.ApprovalPrompt = "force";
req.State = Application.Cryptography.Encrypt(Application.JSON.SerializeToString<State>(new State { UID = userId, PROFILEID = profileId, SUCCESS = request.SuccessUrl, FAIL = request.FailUrl }), Settings.Cryptography.SymetricKey);
// Return the url that the requesting application should redirect to in order to perform the authorization.
return req.Build().ToString();
This successfully gets me an access token and refresh token. Now I wanted to insert a new stream based on the information in the google api docs
var token = new Google.Apis.Auth.OAuth2.Responses.TokenResponse { RefreshToken = refreshToken, AccessToken = accessToken };
var credentials = new UserCredential(new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = "<id>",
ClientSecret = "<secret>",
}
}), string.Empty, token);
var service = new YouTubeService(new BaseClientService.Initializer
{
HttpClientInitializer = credentials
});
var streamResource = new LiveStreamsResource(service);
var result = streamResource.Insert(new LiveStream
{
Snippet = new LiveStreamSnippet
{
Title = "Stream"
},
Cdn = new CdnSettings
{
Format = "1080p",
IngestionType = "rtmp"
}
}, "id, snippet, cdn, status");
var returnedStream = result.Execute();
When this runs Execute() gives the following exception:
Google.Apis.Requests.RequestError
Request is not authorized [403]
Errors [
Message[Request is not authorized] Location[ - ] Reason[insufficientLivePermissions] Domain[youtube.liveStream]
]
I can't figure out what I'm doing wrong in this process. Even the API explorer
Apparently, I was looking at this all wrong (and Google's API documentation should really describe this).
The response isn't that I don't have access to the proper scopes, it's that even though I was authorizing myself for the youtube scope, my youtube account did not have live streams enabled (separate option).
After enabling live streaming on my account this code worked properly.

Facebook C# SDK Post to Page as Page

I have been struggling to get the Facebook C# SDK to post to my page, as the page for a couple of days.
From my googling, I have found that the process should be as follows:
Authorize application for manage_pages and publish_stream with my user account (done through this URL: https://graph.facebook.com/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=publish_stream,manage_pages)
Get user access token
Exchange user access token for long lived access token
Get me/accounts with the long lived user access token
Get the page access token from the result
Post to the page_id/feeds endpoint using the long lived token
I can follow this process through the graph explorer, and it works. A post is created on the page with the generated token.
How do I do this using the C# SDK?
I tried:
dynamic userTokenResult = client.Get("oauth/access_token", new
{
client_id = appid,
client_secret = appsecret,
grant_type = "client_credentials"
});
dynamic longLivedResult = client.Get("oauth/access_token", new
{
client_id = appid,
client_secret = appsecret,
grant_type = "fb_exchange_token",
fb_exchange_token = userTokenResult.access_token;
});
client.AccessToken = longLivedResult.access_token;
// Post the message
dynamic messagePost = new
{
link = message.LinkUrl,
name = message.LinkName,
caption = message.LinkCaption,
description = message.LinkDescription,
message = message.Message
};
// Set the status
var postId = client.Post("pagename/feed", messagePost);
However, I suspect that this is returning the application access_token, not the user access_token (it fails at GET: me/accounts).
you cannot get user token from server-side code (even if you know login/password). You should either:
copy/paste it from Graph API Explorer
Get it from JS SDK client side
Use GetLoginUrl function from FacebookClient to get login URL and redirect the user to that page. After login is completed, facebook will call your function back - and in that function you will be able to the the token. Below are 2 functions (authorize and callback) from my MVC project - but I think you will get the idea.
public ActionResult Authorize(Guid eventId)
{
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = eventId });
var service = new FacebookClient();
var loginUrl = service.GetLoginUrl(new {
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
response_type = "code",
scope = "manage_pages, publish_actions, user_photos, publish_stream" // Add other permissions as needed
});
return new RedirectResult(loginUrl.AbsoluteUri, permanent: false);
}
that will redirect user to the Facebook login page. When user enters credentials and presses login, this function will be called (note the code parameter - it will be used to get the token):
public ActionResult AuthorizeCallback(string code, string eventCode)
{
var redirectUri = ConfigurationProvider.HostingEndpoint + this.Url.Action("AuthorizeCallback", new { eventCode = eventId });
var fb = new FacebookClient();
dynamic result = fb.Post("oauth/access_token", new
{
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
redirect_uri = redirectUri,
code = code
});
var accessToken = result.access_token;
// update the facebook client with the access token so
// we can make requests on behalf of the user
fb.AccessToken = accessToken;
// now get externded app Token
dynamic extendedToken = fb.Get("oauth/access_token", new
{
client_id = ConfigurationProvider.FacebookAppId,
client_secret = ConfigurationProvider.FacebookAppSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = fb.AccessToken
});
// Get the user's information
dynamic me = fb.Get("me");
}
After that you should call "/me/accounts", find your page and get its token from there.
If you're just trying to post to your own page, an alternative is to use Windows PowerShell and http://facebookpsmodule.codeplex.com. This reduces the operation to a few lines of PowerShell script.

Linq to Twitter status update

This is my code
For some reason i am unable to update the status i am getting this error .
Your credentials do not allow access to this resource at
var tweet = twitterCtx.UpdateStatus("Hello world");
var auth = new ApplicationOnlyAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = "",
ConsumerSecret = ""
}
};
auth.Authorize();
//auth.Invalidate();
var twitterCtx = new TwitterContext(auth);
var tweet = twitterCtx.UpdateStatus("Hello world");
i checked my ConsumerKey and Secret are correct and also i gave my app read write acccess. I am able to get the previous status , User Name but i am just unable to tweet a new status
Application Only authorization can only perform operations that are application-level. This differs from other authorizers that let you operate on behalf of a user. The logic is that a user has an account, but an application doesn't. Therefore, you can't tweet on behalf of an application because the tweet can't be assigned anywhere. However, if you tweet on behalf of a user, the tweet goes into that user's list of statuses (their timeline).
LINQ to Twitter has various authorizers and you can see them in use by downloading samples specific to the technology you're using. The downloadable source code also has samples. Here's an example of how to use the PIN authorizer:
static ITwitterAuthorizer DoPinOAuth()
{
// validate that credentials are present
if (ConfigurationManager.AppSettings["twitterConsumerKey"].IsNullOrWhiteSpace() ||
ConfigurationManager.AppSettings["twitterConsumerSecret"].IsNullOrWhiteSpace())
{
Console.WriteLine("You need to set twitterConsumerKey and twitterConsumerSecret in App.config/appSettings. Visit http://dev.twitter.com/apps for more info.\n");
Console.Write("Press any key to exit...");
Console.ReadKey();
return null;
}
// configure the OAuth object
var auth = new PinAuthorizer
{
Credentials = new InMemoryCredentials
{
ConsumerKey = ConfigurationManager.AppSettings["twitterConsumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["twitterConsumerSecret"]
},
AuthAccessType = AuthAccessType.NoChange,
UseCompression = true,
GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
GetPin = () =>
{
// this executes after user authorizes, which begins with the call to auth.Authorize() below.
Console.WriteLine("\nAfter authorizing this application, Twitter will give you a 7-digit PIN Number.\n");
Console.Write("Enter the PIN number here: ");
return Console.ReadLine();
}
};
// start the authorization process (launches Twitter authorization page).
auth.Authorize();
return auth;
}
This method returns an instance of PinAuthorizer, auth, and you can use it something like this:
PinAuthorizer auth = DoPinAuth();
var ctx = new TwitterContext(auth);
ctx.UpdateStatus("Hello LINQ to Twitter!");
* Update *
The preceding code was from the old version of LINQ to Twitter. Here's an example of how to do it with the newer async version:
static IAuthorizer DoPinOAuth()
{
var auth = new PinAuthorizer()
{
CredentialStore = new InMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"]
},
GoToTwitterAuthorization = pageLink => Process.Start(pageLink),
GetPin = () =>
{
Console.WriteLine(
"\nAfter authorizing this application, Twitter " +
"will give you a 7-digit PIN Number.\n");
Console.Write("Enter the PIN number here: ");
return Console.ReadLine();
}
};
return auth;
}
And then you can use it like this:
var auth = DoPinOAuth();
await auth.AuthorizeAsync();
var twitterCtx = new TwitterContext(auth);
await twitterCtx.TweetAsync("Hello LINQ to Twitter!");
For more information, you can find Documentation and Source code. The source code has demos in the New\Demos folder.
There's a method on the TwitterContext named UpdateStatus, which you would use like this:
twitterCtx.UpdateStatus(" Your text goes here ");
You'll need to authorize with OAuth for this to work, so take the PIN option in the demo. After you're authorized, you can call UpdateStatus.

FB Logout with C# sdk

I'm logged in to my app using my FB credentials. In the end I do a logout and remove my session variables. I'm logged out from application, but the FB session remains open although I do a post to the FB logout page with the post like in the code:
if (Session["FBAccessToken"] != null){
var fb = new Facebook.FacebookClient();
string accessToken = Session["FBAccessToken"] as string;
//var logoutUrl = fb.GetLogoutUrl(new { access_token = accessToken, next = "https://www.facebook.com/", });
var logoutUrl = fb.GetLogoutUrl(new { next = "https://www.facebook.com/", });
fb.Post(logoutUrl.AbsoluteUri, new { access_token = accessToken });
Session.RemoveAll();
}
I've tried both: logoutUrl generated with and without access token parameter, neither worked for me.
There has been changes on facebook logout since my last blog post. Here is the way to logout.
var fb = new FacebookClient();
var logoutUrl = fb.GetLogoutUrl(new {access_token = "...", next = "...." });
// redirect to logoutUrl.AbsoluteUri
next url cannot be any arbitrary url. I has to be the one that is part of the site url which you used to retrieve the access token.
#prabir has the answer. Here is a complete answer after I tweaked it for my MVC app. Just replace "localhost:51042/" with whatever URL is appropriate for your app.
This actually fills a hole in the tutorial: http://www.asp.net/mvc/overview/getting-started/using-oauth-providers-with-mvc
public ActionResult LogOff()
{
WebSecurity.Logout();
if (Session["facebooktoken"] != null)
{
var fb = new Facebook.FacebookClient();
var logoutUrl = fb.GetLogoutUrl(new { access_token = Session["facebooktoken"], next = "http://localhost:51042/" });
Response.Redirect(logoutUrl.AbsoluteUri);
Session.RemoveAll();
}
return RedirectToAction("Index", "Home");
}

Categories