facebook api - fb:registration and permissions issue - facebook-graph-api

i'm working with the facebook sdk for php and want the users to sit on my own database but still to get permissions of them.
my very basic use of the
i want to register users to my site via facebook, but i still want to be able to post to thier wall. i thought about only using the facebook login method but then i have no way to ask my customers (Via registration) what is their phone number and the phone number is the most important part i need from the people who register.
i tried to add the scope params to my <fb:registration tag but it seems to ignore it. when i only use the login method via <fb:login-button the permissions issue seems to work.
this is my exact flow:
first, i call the fb:login-button to determine if the client is already reistered:
<fb:login-button scope="publish_stream,user_checkins,email" registration-url="/register" /></fb:login-button>
then, on the registration page i have this code:
<fb:registration
fields='[{"name":"name"},{"name":"gender"},{"name":"email"},{"name":"birthday"},{"name":"location"},{"name":"phone2","description":"mobile phone","type":"text"}]'
redirect-uri="XXXXXX"
fb_only="true"
scope="read_stream,publish_stream"
width="530">
when the user comes back from facebook i use this code:
require_once('facebook-sdk/src/facebook.php');
$facebook = new Facebook(array( 'appId' => $GLOBALS['facebookAppID'], 'secret' => $GLOBALS['facebookAppSecret']));
$customerArray = $facebook->getSignedRequest();
that's works great and create the customer record on my database. but - it does not give the permission i need to post on my user wall.

You can't ask for user permissions in registration using this plugin, but you can do a work around asking for permissions before showing the form. You can make a call to FB.login popup and after the user gives you permissions in the callback function you can show the registration form (which could be hidden while the user accept the permissions).

Related

AWS Cognito custom auth - sending metadata to a challenge lambda functions

I'm developing a custom passwordless auth to sign into a Cognito user pool. I will describe what I'm trying to implement in case anything is silly. I want a user to enter their email address, then receive a magic login link via email, and when they click on that be taken back to the site and be logged in.
This uses custom auth lambda functions to define/create a challenge with a time based password and send it to the user in an email. I am having a couple of problems:
Problem 1)
When the user returns with the code they might not be in the same browser/device and certainly won't be in the same tab so they don't have the session, meaning I need to call cognitoUser.initiateAuth again. This goes through the define/create challenge lambdas again so a second email gets sent even though at this point the user is coming from the email link so already has the code. Note: the session id is not available in the event object when the challenge is created, also I've read these sessions only last 3 minutes and my time based passwords will last ~15minutes, so I don't think I can include the session id in the email.
Problem 2)
You can login from a few places (browser, android app, etc) and I would like to be able to include the url or at least protocol as a parameter to control what gets sent in the email, e.g. if you entered your email address in the android app then the email you get would be myapp://login?code=xxx and if you did it on the web it would be https://example.com/login?code=xxx
It seems like I would be able to implement both of these to work properly if only I could find some way to send custom metadata through to the DefineChallenge and CreateChallenge lambda such that it would appear in the event object. I thought adding ValidationData to the AuthenticationDetails object would do this, but that information doesn't appear in the event object in the Lambda fns.
The workaround I've found is to create a new client id for every situation - one for initiating auth, one for redeeming token, and repeat for each different protocol. But that is a lot of client ids quickly - a pain to mantain and clumsy.
So tl;dr is: I want to send custom metadata from my cognitoUser.initiateAuth(...) call in JS and have it available in my Define/Create Challenge lambda fns.
You can split the authentication process into multiple custom auth challenges. This allows custom auth state to be supplied via the challenge response as client metadata.
Auth session state must be persisted in a database in order to be shared between devices.
Your custom login flow will probably have two challenge steps: the first prompts for auth type and the second prompts for the secret code. The action taken by the "Create Auth Challenge" Lambda will depend on the auth type. If the auth type is "Email" then the secret code and magic link are generated, stored in DynamoDB and emailed. If the auth type is "MagicLink" then the secret is loaded from DynamoDB. Clicking on a Magic link will initiate a new auth session and automatically supply all the challenge answers.
There are a few other things to consider:
Your magic link needs to encapsulate the Cognito username as well as the one-time secret and probably some other session id that is used as a key in dynamodb.
You probably should not put app-specific links into your emails. Instead associate your domain with your app and/or leverage the redirect URI parameter of your web-based login page.
You can also access custom Cognito user attributes from the Lambda function which can be used to indicate user login preferences (eg Email vs SMS for login codes).

Cognito User Pools - Is it possible to create a custom sign up/in form for Facebook login?

I would like to use a Cognito User Pool for Facebook logins only, which may be possible using the built in login form, but I need to use my own.
Theoretically, when it comes to a custom form, it shouldn't be hard: after I receive a user object from FB, I bind the user and email attributes to the ones in my User Pool and I save it.
But what to do about the password field and future authentication? And here I have failed during my journey...
...
userPool.signUp('FoobarUser', '**password?**', attributeList, null, function(err, result){
...
While digging deeper into the docs, I tried to implement a Identity Pool (Federated Identities), managed to save user info in the form of datasets as well, but then I realised, querying these sets gonna be a huge pain if possible at all.
Maybe I'm failing to understand the concepts, I would be really thankful if someone could suggest a way to manage facebook logins in a nicely organised fashion using Cognito.
So here is what I understand from your query.
Setup
Link Facebook to userpool
The app client allows only Facebook login, no other providers allowed (not even Userpool)
On login, you want Facebook user's info to be automatically populated in your Userpool
You don't want to use Cognito's builtin UI but use your own
My 2 Cents
In your app client, just select Facebook
In your UI, have a login button. On clicking it should redirect to your userpool's authorization endpoint
https://your_domain.auth.us-east-1.amazoncognito.com/oauth2/authorize?redirect_uri=https://www.example.com&response_type=token&client_id=your_appclient_id
If you want to use your own UI with multiple providers, allow the same in Client and on clicking the appropriate button in your UI (say Facebook), redirect users to the authorize endpoint but append the identity_provider in the URL
https://your_domain.auth.us-east-1.amazoncognito.com/oauth2/authorize?redirect_uri=https://www.example.com&response_type=token&client_id=your_appclient_id&identity_provider=Facebook
If you want to see the names of all supported identity providers, use ListIdentityProviders API call
This way, all Facebook users will be automatically created in your userpool. Of course, their names will be random like Facebook_123jkjdwj but all their details will be correctly populated from the token as per your attribute mapping. As a plus, all auto-created users from a particular provider are added to an auto-created group 'Userpoolid_providername' eg. us_east_1_xxxx_Facebook.

Authenticating user entered User-Name and Password, in an Ionic 2 App's login screen, with Azure Active Directory using ADAL Library

I am developing an Ionic 2 App that is authenticating users against Microsoft Azure Active Directory. Having trouble in figuring out how to implement the following flow using ADAL:
User enters "user-name" and "password" ==> Clicks on Login button ==> App makes Azure AD call by passing over the user entered "user-name" and "password" ==> Azure AD authenticates the user and returns back the result.
Following the Azure AD documentation, I was able to successfully implement "server-flow" where on making an Azure AD call, it opens up a new Microsoft Azure-AD login page for my app to enter "user-name" and "password". And upon successful authentication the user is landed back on to my app's home-page. This works fine but the experience is not great from UX perspective.
Following is the way I did it:
myAzure = new WindowsAzure.MobileServiceClient(MY_AZURE_APP_SERVICE_URL);
myAzure .login('aad').then(
(result) => {
//Successful Login
},
(err) {
console.log("In client.login callback failed");
});
});
Then, I followed Azure AD documentation to implement "client-flow". I have a question in this:
1. How do I pass in the "user-name" and "password" to Azure AD when I make "authContext.acquireTokenSilentAsync()" call or "authContext.acquireTokenAsync()" call.
Upon going through the implementation of these methods in the ADAL library, it appears that
"authContext.acquireTokenSilentAsync()" can accept only user-name and not the password. So, is it safe to assume that this method is not supposed to be used for login purposes?
"authContext.acquireTokenAsync()" can accept user-name but in addition, there is a parameter called "extraQueryParameters". Am I supposed to use this parameter to pass in the password? However, this is supposed to open-up a login page for the user on the screen. It did open a new login page on my device. So not sure how to develop my functionality.
If both of the above ways are not the right way to implement my flow of authentication then can somebody please help me by giving some pointers, links or sample links on how I can implement this?
My app's users are going to be in our corporate Azure-AD. I have created a separate Azure-AD Tenant for my app (also created the required setup so that it's tied up with my Azure App Service, etc.) and I would add users to this tenant when required.
Thank you.
Based on my understanding, the Client-managed authentication flow enables you to provide a single sign-on experience for users or to retrieve additional user data from the identity provider.
That's mean if you doesn't authenticate the identity data provider before mobile authentication, it still require to prompt the users to enter their username and password.
"authContext.acquireTokenSilentAsync()" can accept only user-name and not the password. So, is it safe to assume that this method is not supposed to be used for login purposes?
This method is designed for get the token silently via getting the token from cache or renew the token using the refresh token. It is not designed for this purpose.
"authContext.acquireTokenAsync()" can accept user-name but in addition, there is a parameter called "extraQueryParameters". Am I supposed to use this parameter to pass in the password? However, this is supposed to open-up a login page for the user on the screen. It did open a new login page on my device. So not sure how to develop my functionality.
No. You are not able to pass the password using this function. It will prompt users to enter their username and password by default. However if you have sign-in the Azure AD, you can acquire the access token without prompt via specify the PromptBehavior.Never like below:
var resoult = authContext.AcquireTokenAsync(resource, clientId,new Uri("http://localhost"),new PlatformParameters( PromptBehavior.Never)).Result;
Console.WriteLine(resoult.AccessToken);

Posting to my own facebook wall via Koala

I am trying to post to my own facebook wall. So I created an "app" in my
personal facebook page, and got the app_id, app_secret, etc.
I then did this code:
#oauth = Koala::Facebook::OAuth.new(app_id, app_secret, callback_url)
#token = #oauth.get_app_access_token
#graph = Koala::Facebook::API.new(#token)
foo = #graph.get_object('me')
However, I get this error:
An active access token must be used to query information about
the current user. [HTTP 400]
(Koala::Facebook::AuthenticationError)
The token is valid, I checked. I need to post to my OWN wall, not a
different user's. From what I've read in the documentation, I need an "app
access key", not a "user access key" to do this. I am somewhat new to
the facebook api list, so I think I'm missing something very basic.
You can use an app token instead of a user token to post to a wall as long as the user already granted the proper permissions to your application.
That is, in timeline
User grants app access to post with publish_actions
User access token supplied by Graph Login Flow
At this point, you can either use the user access token or application access token
In addition,
foo = #graph.get_object('me')
is not a POST request. It says, get the object from the graph named me. Further me will not resolve to anything if you are using an application token because there is no way for the application to tell which "me" in all the users in the app you are referring to. Thus you need to refer to the app scoped id for the user.
e.g
foo = #graph.get_object('4')
Where 4 is a numerical app scoped ID (4 will not work in your case you need to figure out the correct ID for your application). The correct call in koala will be something like
foo = #graph.put_connections("4", "feed", :message => "I am writing on my wall!")
My problem was that the user (in this case myself) has to allow access to my app to post to my wall.
The full OAuth process is described well at http://developers.facebook.com/docs/authentication/
But specifically, I need to get a URL that I have to visit and then say "yes" to the authnetication question. The code is here:
#oauth = Koala::Facebook::OAuth.new(app_id, app_secret, callback_url)
#oauth.url_for_oauth_code(:permissions => "publish_actions")
The URL will look something like this:
https://www.facebook.com/dialog/oauth?
client_id={app_id}&
redirect_uri={redirect-uri}&scope=publish_actions
Note, the URL has to specify what permissions you want to request from the user (in this case, permission to post to the wall). This permission request is specified under the "scope" variable. Note some version of the facebook api allow posting through the "publish_stream" scope and other versions require the "publish_actions" scope. More information about the permissions available under scope variable is available here: https://developers.facebook.com/docs/facebook-login/permissions/v2.0
When you visit the URL that is generated from the above statement, facebook will give you a message asking if that particular app has permission to post to your wall. You, of course, say "yes". After that, your facebook app can post to the facebook wall using the "app access token"
After that, it's easy to post to the wall with your app access token. The code that works for me is:
#oauth = Koala::Facebook::OAuth.new(app_id, app_secret, callback_url)
#app_access_token = #oauth.get_app_access_token
#graph = Koala::Facebook::API.new(#app_access_token)
foo = #graph.put_connections(facebook_user_id, "feed", :message => "Test message")

Create Custom Registration Pipeline Using python-social-auth

I have a django-based site that has private content and a small number of necessary users. I would like for everyone to use their Google account to authenticate using python-social-auth (PSA). I would therefore like to use the following process to add new users:
The new user visits the site and clicks on a "request access" button.
PSA would create a disabled user. The requesting user would be redirected to a page stating that access will be granted within 24 hours if approved.
The site admin would receive an email message notifying her of the request. If the new user is approved, then his account is enabled and the user is notified. If the request is not approved then the disabled account is deleted.
Once the user is enabled, he will login using the pipeline from this tutorial that only authenticates registered users. That part's easy. The hard part is figuring out how I'm going to register users but not authenticate them.
I tried extending the SOCIAL_AUTH_PIPELINE by adding a custom pipeline function that disables users if they're new. However, the pipeline continues to execute at that time, and it appears that it then tries to authenticate the new, disabled user. I say this because I'm redirected in my app to this URL:
http://myapp.com/accounts/login/?next=/
...which for me is a 404. This URL seems to be generated by PSA.
So here are my questions:
Is it possible for me to drop out of the SOCIAL_AUTH_PIPELINE and redirect my user to a "please wait for authorization" screen if they're a new user? I don't think that I can use a "partial pipeline" for this because I don't want to pick up the pipeline again later - I just want to "drop out" if this is a new user.
If that's not possible, then what's option B? Is it creating a custom pipeline that only handles registration? If so, then how would one do that?
You can keep your pipeline that flags the user as disabled, but also define this setting SOCIAL_AUTH_INACTIVE_USER_URL = "/wait-for-activation" (point it to the URL that shows the "wait for activation" page).