No 'Access-Control-Allow-Origin', only errors on first call but works subsequently - facebook

I have an AngularJS app which is trying to auth with my Web Api. I receive the below error during the first call to my server if the user does not exist in my database, but does not happen on subsequent calls to the same method once the user exists in my db. (relevant code at the bottom)
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:1378' is therefore not allowed access. The response had HTTP status code 500.
The flow of the logic is:
AngularJS auths with Facebook when the user clicks login
App does an $http.post to my server for auth/login passing their credentials
Server polls Facebook API for user details
If user exists, update their profile and auth 'em
Else, create new membership user, update with FB details, and auth 'em
The only thing that's different if they don't exist in the database (which is when the defect occurs) is that the login method asynchronously calls a createUser method then returns data. No additional external calls are made.
API startup method enabling CORS:
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
var cors = new EnableCorsAttribute("*","*","*");
config.EnableCors(cors);
ConfigureOAuth(app);
app_start.WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
API Controller:
[Route("Login")]
[HttpPost]
[AllowAnonymous]
public async Task<FacebookUserModel> Login(FacebookUserRequest user)
{
FacebookUserModel fbUser = new FacebookUserModel();
// Build FacebookUser object
try {
// Grab basic user details
string profileRequestUri = "https://graph.facebook.com/" + user.fbID + "?access_token=" + user.access_token;
HttpWebRequest profileRequest = (HttpWebRequest)WebRequest.Create(profileRequestUri);
profileRequest.Method = WebRequestMethods.Http.Get;
profileRequest.Accept = "application/json";
HttpWebResponse profileResponse = (HttpWebResponse)profileRequest.GetResponse();
Stream profileResponseStream = profileResponse.GetResponseStream();
StreamReader profileStreamReader = new StreamReader(profileResponseStream);
fbUser = JsonConvert.DeserializeObject<FacebookUserModel>(profileStreamReader.ReadToEnd());
} catch (Exception) ...
try {
// Grab profile picture
string pictureRequestUri = "https://graph.facebook.com/" + user.fbID + "/picture";
HttpWebRequest pictureRequest = (HttpWebRequest)WebRequest.Create(pictureRequestUri);
pictureRequest.Method = WebRequestMethods.Http.Get;
HttpWebResponse pictureResponse = (HttpWebResponse)pictureRequest.GetResponse();
fbUser.profilePictureUri = pictureResponse.ResponseUri.ToString();
} catch (Exception) ...
// If user exists, change password to new token and return)
if(userExists)
{
try {
IdentityUser identityUser = _repo.FindUser(ID, pass).Result;
FacebookUserModel dbUser = db.FacebookUserObjects.First(u => u.identityUserID == identityUser.Id);
db.Entry(dbUser).CurrentValues.SetValues(fbUser);
db.SaveChangesAsync();
fbUser.identityUserID = identityUser.Id;
return fbUser;
}
catch (Exception e)
{ return null; }
}
// Else, create the new user using same scheme
else
{
UserModel newUser = new UserModel
{
UserName = ID,
Password = pass,
ConfirmPassword = pass
};
// Create user in Identity & linked Facebook record
createUser(newUser, fbUser);
return fbUser;
}
}
private async void createUser(UserModel newUser, FacebookUserModel fbUser)
{
IdentityResult result = await _repo.RegisterUser(newUser);
var identityUser = await _repo.FindUser(newUser.UserName, newUser.Password);
fbUser.identityUserID = identityUser.Id;
db.FacebookUserObjects.Add(fbUser);
db.SaveChangesAsync();
}
AngularJS calls to my server:
var _login = function (fbID, fbToken) {
$http.post(serviceBase + 'auth/login', { "fbID": fbID, "access_token": fbToken }).then(function (response) {
var data = "grant_type=password&username=" + fbID + "&password=" + pass;
$http.post(serviceBase + 'auth/token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } })
.success(function (tokenResponse) {
authServiceFactory.bearerToken = tokenResponse.access_token;
})
.error(function (err) {
console.log("token error:", err);
});
authServiceFactory.userObject = response.data;
window.localStorage['userObject'] = JSON.stringify(authServiceFactory.userObject);
})
};
Why would I get the No 'Access-Control-Allow-Origin' error only on the first call, but not subsequent ones?
Update
I have a workaround in place that works, but I don't really like. The issue only arose when calling a second method from my login controller, so if I moved that code up into the login controller instead of a secondary method it works without the CORS error. This really bothers me though and is inefficient, I'd love to know a better way around it.

if you're working with angularjs you might want to check out satellizer. It makes the auth process really simple and has some awesome built in window popup control.
As far as the Access-Control-Allow-Origin calls it could be happening because you explicitly set headers on the one call and the other ones are falling back to the default http provider? Check out $http and see if providing those defaults might work around it.

Related

How can I get "Amazon.Extensions.CognitoAuthentication.CognitoUserSession.IDToken" From AWSCredentials?

I want get "Amazon.Extensions.CognitoAuthentication.CognitoUserSession.IDToken" From AWSCredentials.
I have AWSCredentials From Oauth Google Login.
public AWSCredentials GetAWSCredentials_Google(string token)
{
CognitoAWSCredentials credentials = new CognitoAWSCredentials(FED_POOL_ID, regionTable[REGION]);
credentials.AddLogin("accounts.google.com", token);
return credentials;
}
And, I use EC2 Instance and my ubuntu server is in there. Also, I was originally using a method of accessing the server by receiving a membership from Cognito User Pool, so I was using the following code.
private IEnumerator sendPostUser()
{
string uri = rootUrl + "/user";
string json = "{ ... }";
byte[] jsonData = System.Text.Encoding.UTF8.GetBytes(json);
using (UnityWebRequest request = UnityWebRequest.Post(uri, json))
{
if (request.uploadHandler != null)
request.uploadHandler.Dispose();
request.disposeUploadHandlerOnDispose = true;
request.disposeDownloadHandlerOnDispose = true;
request.uploadHandler = new UploadHandlerRaw(jsonData);
/* Header */
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("token", cloud_acess.GetComponent<ControlCloud>().cognitoUser.SessionTokens.IdToken);
/* Send Message */
yield return request.SendWebRequest();
...
}
By the way, there was a problem with this code "request.SetRequestHeader("token", cloud_acess.GetComponent().cognitoUser.SessionTokens.IdToken);".
This cognitouser means Amazon.Extensions.CognitoAuthentication.CognitoUser.
My Project get CognitoUser using user's ID and PW, and get AWSCredentials using this Cognitouser. But Google Login doesn't this process and just get credentials.
So, I can't get "cognitoUser.SessionTokens.IdToken". It makes me cannot to request anything from ec2 server.
How Can i get this? What should I do if the premise of this problem itself is wrong?
I tried to put all the tokens I received when I logged in to Google and the tokens I received as credentials in the header.But I failed.

Identity server stuck in redirect loop

I'm using identityserver4 for single sign-on. For most of the time application function smoothly but intermittently we face a redirect loop issue which becomes a show stopper for us until we restart's our app service. The page goes on loading continuously before finally showing a 'Bad request - Request Too Long' page with message: HTTP Error 400. The size of the request headers is too long. If we check the network tab, we can see that the application is looping between the identity server and client application redirect sign in pages. The application insight tells us that the client app gives a 401 on his home/index page and then a 302 on the signin-oidc url, then goes to the identity server connect/token, then connect/userinfo endpoints to get claims and comes back to the client home/index page to again get a 401. The loop continues (Identity server says user is authenticated while client says it is not). We are unable to find a fix for this since long. Any help is appreciated. Attaching the client side configuration for reference.
Findings
Our client app is an mvc app & we have used Session's & TempData in few area's. This areas are the triggering point of the redirect issue. What we have observed is, when the client initially login the authentication cookie is created (Cookie Name: AudDiscoveryAuth) and I could see it being passed in header for each request made to the controller actions. But once the user visit's any such area where we have used Session/TempData and Log out or any other user tries to login, Identity server successfully authenticates the user also the userendpoint to retrieve the details is being invoked however the cookie itself is not being created and is missing in every request to the Index/Home action method hence the redirect loop. Wondering what could be hampering in issuing cookie when using session variable elsewhere in the application or is their a setting missing.
Also in every redirect the occurrence of OpenIdConnect.nonce.XXX cookie is incremented. Once the count of OpenIdConnect.nonce.XXX reaches more then a certain level we get the bad request error page
public void Configuration(IAppBuilder app)
{
string baseClientAddress = ConfigurationManager.AppSettings["ApplicationUrl"];
int slidingExpiryHrs = Convert.ToInt32(ConfigurationManager.AppSettings["SlidingExpiryHrs"]);
int slidingExpiryMins = Convert.ToInt32(ConfigurationManager.AppSettings["SlidingExpiryMins"]);
TimeSpan expireTimeSpan = new TimeSpan(slidingExpiryHrs, slidingExpiryMins, 0);
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationType,
CookieName = "AudDiscoveryAuth",
ExpireTimeSpan = expireTimeSpan,
SlidingExpiration = true
});
app.UseOpenIdConnectAuthenticationPatched(new OpenIdConnectAuthenticationOptions
{
ClientId = "ratingspro.web",
Authority = IdsvrConstants.BaseAddress,
RedirectUri = baseClientAddress + "signin-oidc/",
PostLogoutRedirectUri = baseClientAddress + "signout-callback-oidc/",
ResponseType = "code id_token",
Scope = "openid api1 ratingspro.webapi offline_access",
UseTokenLifetime = false,
SignInAsAuthenticationType = DefaultAuthenticationType,
RequireHttpsMetadata = true,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthorizationCodeReceived = async n =>
{
var client = HttpClientFactory.Create();
var tokenResponse = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest
{
Address = IdsvrConstants.TokenEndpoint,
ClientId = "ratingspro.web",
ClientSecret = "secret",
Code = n.Code,
RedirectUri = n.RedirectUri,
});
if (tokenResponse.IsError)
{
LogHelper.LogMessage("RatingsproApp: Startup => tokenResponseError: " + tokenResponse.Error);
throw new AuthenticationException(tokenResponse.Error);
}
var userInfoResponse = await client.GetUserInfoAsync(new UserInfoRequest
{
Address = IdsvrConstants.UserInfoEndpoint,
Token = tokenResponse.AccessToken
});
if (userInfoResponse.IsError)
{
throw new AuthenticationException(userInfoResponse.Error);
}
var claims = userInfoResponse.Claims;
if (claims.Any(c => c.Type == "ApplicationAccessDenied"))
{
throw new AuthenticationException(claims.FirstOrDefault(c => c.Type == "ApplicationAccessDenied").Value);
}
// create new identity
var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
id.AddClaims(claims);
id.AddClaim(new Claim("AccessToken", tokenResponse.AccessToken));
id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString(CultureInfo.InvariantCulture)));
id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
client.Dispose();
n.AuthenticationTicket = new AuthenticationTicket(
new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token").Value;
n.ProtocolMessage.IdTokenHint = idTokenHint;
}
return Task.FromResult(0);
},
AuthenticationFailed = x =>
{
x.ProtocolMessage.RedirectUri = "/";
return Task.CompletedTask;
}
}
});
}
}

Add a user manually on server side and set their session

I can't seem to understand the relation between Accounts.createUser() and Accounts.onCreateUser(). I have an external api that validates the users' login credentials. Once the api sends me a positive response, I need to add the user in MongoDB and start its session so it can be considered as a logged in user. Accounts.createUser() is creating a user on server side, but I need Accounts.onCreateUser() because I need to add custom fields like user's token that is being generated from the external api.
This is the code I have right now (which doesn't add a user at all):
server-side code:
var request = {
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
'params': user
};
try {
var response = HTTP.call('POST', url, request); //send call to the external api
var token = response.data.token;
//decode the token and add the user in the database
var userInfo = Base64.decode(token.split('.')[1]);
var options = {
email: user._username,
profile: {
name: user._username
},
token: token
};
var user = Accounts.onCreateUser(function(options, user) {
if (options.token)
user.token = options.token;
if (options.profile)
user.profile = options.profile;
return user;
});
console.log(user); //this returns undefined
return JSON.stringify({
'code': 200,
'token': userInfo
});
} catch (error) {
console.log(error);
//console.log(error.response);
var body = error.response.content;
return body;
}
Okay. So I finally found what I had been looking for. The relation between Accounts.createUser and Accounts.onCreateUser is that Accounts.onCreateUser is a hook and adds extended functionality to the original Accounts.createUser function. What is the extended functionality? It lets you create additional fields prior to actually inserting your user in the database. You have to write this hook in your main.js (server side) in the startup code snippet:
Meteor.startup(() => {
Accounts.onCreateUser(function(options, user) {
if (options.token)
user.token = options.token;
if (options.profile)
user.profile = options.profile;
return user;
});
})
And wherever you want to add the user, simply call Accounts.createUser() and this hook will be called automatically prior to the createUser call

How can i post the feed to facebook page as admin using c# sdk?

I want to update the facebookpage using c# sdk. I have partially successful with this, the problem is whenever I post messages to the page, post is visible only for admin(i am the admin of the page)is logged In. I want the post or feed to be visible to every one who visit the page.
(even admin is logged out post's are not visible to admin also)
The following code i am trying to achieve
public ActionResult FacebookPagePost()
{
string app_id = "xxxx";
string app_secret = "xxx";
string scope = "publish_stream,manage_pages";
string page_Id = "xxX";
if (Request["code"] == null)
{
return Redirect(string.Format(
"https://graph.facebook.com/oauth/authorize?client_id={0}&redirect_uri={1}&scope={2}",
app_id, Request.Url.AbsoluteUri, scope));
}
else
{
try
{
Dictionary<string, string> tokens = new Dictionary<string, string>();
string url = string.Format("https://graph.facebook.com/oauth/access_token?client_id={0}&redirect_uri={1}&scope={2}&code={3}&client_secret={4}",
app_id, Request.Url.AbsoluteUri, scope, Request["code"].ToString(), app_secret);
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
string vals = reader.ReadToEnd();
foreach (string token in vals.Split('&'))
{
tokens.Add(token.Substring(0, token.IndexOf("=")),
token.Substring(token.IndexOf("=") + 1, token.Length - token.IndexOf("=") - 1));
}
}
string access_token = tokens["access_token"];
var client = new FacebookClient(access_token);
dynamic fbAccounts = client.Get("/me/accounts");
dynamic messagePost = new ExpandoObject();
messagePost.picture = "http://pic.com/pic.png";
messagePost.link = "http://www.examplearticle.com";
messagePost.name = "name goes here";
messagePost.description = "description goes here";
//Loop over the accounts looking for the ID that matches your destination ID (Fan Page ID)
foreach (dynamic account in fbAccounts.data) {
if (account.id == page_Id)
{
//When you find it, grab the associated access token and put it in the Dictionary to pass in the FB Post, then break out.
messagePost.access_token = account.access_token;
break;
}
}
client.Post("/" + page_Id + "/feed", messagePost);
}
catch (FacebookOAuthException ex)
{
}
catch (Exception e)
{
}
}
}
1) Create a Facebook App at: developers.facebook.com and get yourself an APPID and APPSECRET. (there are a lot of tutorials online for doing this so I will skip repeating it)
2) Go to: http://developers.facebook.com/tools/explorer and choose your app from the dropdown and click "generate access token".
3) After that do the following steps here:
https://stackoverflow.com/questions/17197970/facebook-permanent-page-access-token to get yourself a permanent page token.
(I can not stress this enough, follow the steps carefully and thoroughly)*
*I have tool I built that does this for me, all I enter is the APPID, APPSECRET and ACCESSTOKEN which the tool then generates a permanent page token for me. Anyone is welcomed to use it and help make it better,
https://github.com/devfunkd/facebookpagetokengenerator
=========================================================================
Ok at this point you should have your APPID, APPSECRET and a PERMANENT PAGE TOKEN.
=========================================================================
In your Visual Studio solution:
4) Using Nuget:Install-Package Facebook
5) Implement the Facebook client:
public void PostMessage(string message)
{
try
{
var fb = new FacebookClient
{
AppId = ConfigurationManager.AppSettings.Get("FacebookAppID"),
AppSecret = ConfigurationManager.AppSettings.Get("FacebookAppSecret"),
AccessToken = ConfigurationManager.AppSettings.Get("FacebookAccessToken")
};
dynamic result = fb.Post("me/feed", new
{
message = message
});
}
catch (Exception exception)
{
// Handle your exception
}
}
I hope this helps anyone who is struggling to figure this out.

Facebook login stuck in permissions page in dispaly=touch mode- windows 8

I was trying to implement Facebook login in windows 8 application . I am using following url to request Facebook login
https://www.facebook.com/dialog/oauth?client_id=APP_ID&response_type=token&scope=email%2coffline_access%2cpublish_stream&redirect_uri=http%3a%2f%2fwww.facebook.com%2fconnect%2flogin_success.html&display=touch
I am using webview to request this url .I am getting the login page correctly shown below.
After user enter login credential it is getting redirecting to another page and getting stuck there.I guess that page is supposed to be given permissions.I am attaching a screen shown below
Nothing will happen if i click on cancel or install ..
if i am removing display=touch from the request everything will works fine.But the login poge and permissions page are displayed like in web browser.That is not optimized for touch ..
I have tested the same with webbrowser control in wpf..But the problem is still exisiting there. Any ideas?
On Windows 8 You should be using WebAuthenticationBroker.
Here is code example:
private async void Authenticate()
{
//Facebook Authentication Uri
var facebookUri = "https://www.facebook.com/dialog/oauth";
//Standard redirect uri for desktop/non-web based apps
var redirectUri = "https://www.facebook.com/connect/login_success.html";
//Place your appa client id here
var clientId = "";
//The type of token that can be requested
var responseType = "token";
//Response pattern
var pattern = string.Format("{0}#access_token={1}&expires_in={2}", redirectUri, "(?.+)", "(?.+)");
try
{
String FacebookURL = "https://www.facebook.com/dialog/oauth?client_id=" +
clientId + "&redirect_uri=" + Uri.EscapeUriString(redirectUri) + "&scope=read_stream&display=touch&response_type=token";
System.Uri StartUri = new Uri(FacebookURL);
System.Uri EndUri = new Uri(redirectUri);
WebAuthenticationResult WebAuthenticationResult = await WebAuthenticationBroker.AuthenticateAsync(
WebAuthenticationOptions.None,
StartUri,
EndUri);
if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.Success)
{
var response = WebAuthenticationResult.ResponseData.ToString();
}
else if (WebAuthenticationResult.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
//Handle HTTP error
}
else
{
//Handle error
}
}
catch (Exception ex)
{
//Handle error
}
}