How to lookup SSO user in Disqus? - single-sign-on

I have SSO working in Disqus, so that my authenticated users can automatically post to my Disqus forum without separate authentication. However, I cannot find a way to whitelist my SSO users via a server-side API call. It seems that my SSO users are not recognized in any user-related calls to the API.
I've tried calling whitelists/add with both user=[userid] and email=[email], passing the exact userid and email with which I setup the SSO user. No error is returned with the userid, but it does nothing. Passing the email throws an error.
I've tried locating the Disqus user id or username for my SSO users via the users/detail API via:
user=myuserid (the same id used for SSO)
email=myuser#email.com (the same email used for SSO)
user=remote:forumshortname-myuserid
user:username=forumshortname-myuserid
No luck.
API calls to /listUsers and /users/detail do not list my sso users at all, so I cannot retrieve their user handles that way.
The frustrating thing is that I can see the users in the UI console here:
https://disqus.com/api/sso/users/
for the domain (as opposed to the forum), so I know this data exists. But I can't find a way via API to reach it.
Does anyone have this working?

As far as the Disqus API is concerned, the user ID and username of an SSO user is the one that is assigned by Disqus, and not the site. They're unique across the Disqus network, even though they're local to your site only.
However, if you have your own local user ID, you can do a reverse lookup of the Disqus username for the purposes of using the API. The pattern is {sso_slug}-{user_id_md5}
Assuming your SSO remote domain slug is example, you can retrieve the Disqus username like this in python:
import hashlib
def get_disqus_username(user_id):
m = hashlib.md5(user_id)
hashed_id = m.hexdigest()
return 'example-' + str(hashed_id)
Now you can make API requests like this:
GET https://disqus.com/api/3.0/users/details.json?api_key=YOUR_PUBLIC_KEY&user=username:DISQUS_USERNAME

Related

Facebook GraphQL - How to get a users email address and name from backend

I have an app where the user logs into Facebook (and thus has an Auth Token) and then sends that token to my server for authentication within the app.
If it's the users first time in the app, I need to sign them up as well (gather email and name)
Using the users FB auth token (and any server-side tokens) how do I retrieve the user's email address and name? (What endpoints do I need to hit with what tokens/body?)
--
Additional Info:
The login is scoped with ['public_profile', 'email']
The application is running in Node.js on AWS Lambda, and I'd prefer to make a simple fetch if possible instead of installing a whole gql client.
I have tried looking at their graphQL documentation, but I can't
seem to make heads or tails out of it.
I do have access to the user's ID (example: 10157426730xxxxxx)
This would be the API call to get the name and email of a user, with a User Token:
https://graph.facebook.com/me?fields=name,email&access_token=xxxx
Alternatively, you can add the version:
https://graph.facebook.com/v4.0/me?fields=name,email&access_token=xxxx
All the existing fields for users are here to find: https://developers.facebook.com/docs/graph-api/reference/user/
You do not need the User ID, the User Token identifies the User anyway and you can just use "me" instead of the ID. The Graph API is a REST API though, not GraphQL.

Is it possible to add more than one email per user in Keycloak?

I'm using Keycloak for Identity Brokering through Google, Microsoft, etc. But Keycloak only allows one email per user. So the user can be authenticated only through one of the social login options (Google if gmail is added as user's email address, etc.). Is there any way to include more than one email per user, or any other workaround?
EDIT: (Editing based on comments to make scenario more clear)
In my scenario, I'm using a federated user store which contains a large number of users and and I need Keycloak to access all the emails linked to a user when that user is logging in using Google,Azure,etc. because Keycloak is using the email as the unique identifier for the authentication response from the social login provider. Without having the required email as the main email, Keycloak won't allow that user to log in through social IdP
Although, Keycloak emphasises on keeping a unique email,but there are certain scenarios where you may want to keep , say, secondary email.
This can be achieved in a couple of steps:
1. Add a custom attribute for secondary email in user like this:
2. Next , in your client create attribute mapper like this:
When I generated the token after above configuration, the new attribute was avialble in token. You can use this attribute in your app as you desire.
Parsed JWT:
I figured out the best way to deal with this is through the custom user provider (federated user store). Even though we can't add multiple emails per user through the Keycloak admin console, we can write the user provider in such a way that it can get all the emails linked to a user from our database and assign them to the email attribute of each user. Once this is done, all the emails will appear on the admin console as well.
For the social login to recognize those emails, we have to get all the emails linked to a user in the provider to an array and iterate through it until the authentication is complete. This would help to create the social login link to the user through First Login Broker authentication flow.
This is a crude way to approach this, but nevertheless it works!

keycloak - realm resolution based on username (email address)

I'm working on a multi tenant project where usernames are actually their email addresses and the domain of the email serves as a tenant identifier.
Now in keycloak I'll have different realms per tenant, but I want to have a single login page for all tenants and the actual realm that will do the authentication to be somehow resolved by the username (email address).
How do I go about doing that?
I found a thread on the mailing list (that I cant find now...) that discussed the same problem. It was something along the lines of - create a main realm that will "proxy" to the others, but I'm not quite sure how to do that.
I think Michał Łazowik's answer is on the right track, but for Single-Sign-On to work, it needs to be extended a little.
Keep in mind that because of KEYCLOAK-4593 if we have > 100 realms we may have to have multiple Keycloak servers also.
We'll need:
A separate HTTP server specifically for this purpose, auth-redirector.example.com.
An algorithm to determine the Keycloak server and realm from a username (email address).
Here would be the entire OAuth2 Authorization Code Flow:
An application discovers the user wants to log in. Before multiple realms, the realm's name would be a constant, so the application would redirect to:
https://keycloak.example.com/auth/realms/realname/protocol/openid-connect/auth?$get_params
Instead, it redirects to
https://auth-redirector.example.com/?$get_params
auth-redirector determines if it itself has a valid access token for this session, perhaps having to refresh the access token first from the Keycloak server that issued it (the user could have logged out and is trying to login as a different user that is served by a different realm).
If it has an valid access token we can determine the Keycloak server and realm from the username or email address in the access token and redirect to:
https://$keycloak_server/auth/$realm/realname/protocol/openid-connect/auth?$get_params
from here, the OAuth2 Authorization Code Flow proceeds as usual.
Else if it doesn't have a a valid access token, the auth-redirector stores the original app's $get_params as session data. It presents a form to the user asking for a username. When the user submits that, we can determine the Keycloak server and realm to use and then auth-redirector itself logs in to the Keycloak server using its own $get_params. Once the auth-redirector gets a call-back, it retrieves the access+refresh token from the Keycloak server and stores them in session data. It then, finally, redirects back to that same keycloak server and realm with the callers original $get_params (from session data). And the OAuth2 Authorization Code Flow proceeds as usual.
This is definitely a hack! But I think it could work. I'd love to try it out some day, time permitting.
Other hacks/solutions are needed for other OAuth2 flows...
The idea from the mailing list is to write a service (let's say auth-redirector.example.com) that has a single input field for email, finds realm based on domain and redirects to that realm's keycloak endpoint (e.g. auth.example.com/auth/realms/realm-name/etc…) while keeping all GET params.
You can find examples of direct login/registration URLs here: https://lists.jboss.org/pipermail/keycloak-user/2016-July/007045.html
One usability problem is that users would have to provide their email twice, I have not yet found a way to pass the username via the login URL.

Oauth2: authorize access based on unguessable url in email

Our application uses oauth2 & openid connect for auth&auth. It's built using an angular client that calls a REST API. I would like to know how to authorize access to the API, based on the possession of an unguessable url.
I'll explain this a little more. In the application, a user can invite another user. When this happens, an email is sent to the second user. When user 2 clicks a link in the email, he is sent to a webpage with details about the invitation.
Only user 2 should be allowed to see the invitation page. I was planning to solve this by using an 'unguessable url' in the email. Upon visiting the url, the user must somehow be authorized to fetch the invitation details from the API.
The question: how do I authorize a user, based on knowing the unguessable url? How do I assign a claim when the page is loaded, and how do I verify this claim in the API call that follows? The only solution I see, is to set a cookie containing a token. But this is not in line with our existing auth mechanism. I prefer not writing my own token validation code, and let the Identity Provider handle this.
Additional info: user 2 may or may not have an account in the system, and he may or may not be logged in. Neither should prevent the user from seeing the invitation details. In other words: a totally unknown user should be able to see the page. The knowledge of the url should be the only requirement.
Any solution to this problem? Or am I handling it all wrong?
After asking around, the general consensus is to NOT let the external auth mechanism take care of this, but to validate the link ourselves.
The solution is to turn the unguessable part of the url (the 'link id') in some kind of token, which can be validated upon calling the API. This is done by the API itself, not by the Identity Server.
Applied to the invitation issue: when an invitation is created, store the link id together with some info, i.e. what kind of access it allows (invitation access) and the id of the invitation. When the user calls the API to get the invitation, pass the link id for validation. Match the invitation id with the invitation id stored in the link, and if it doesn't, throw an error.

REST API and client on same server, need API authentication?

First, let me describe the application: we are working on a web-based software which is some kind of custom help desk application. It requires the user to login (we use FOSUserBundle). After login the user is redirected to the dashboard. From the dashboard there is no more page reload, the frontend is build on Angularjs and the user can get anywhere within the application without page reload. You could speak of a single page application.
So the data that is presented to the user, is fetched from a rest api (we use FOSRestBundle). This works quite well at this point.
There is some kind of dilemma. Only our staff will access this application (for now). So a staff member needs to login to access the helpdesk. The data that is pushed to the frontend via angularjs is called via api, so the user that has just logged in needs to authenticate again on every request because of rest.
Problem: Since the backend runs on symfony2 let us just try to get the user object of the currently logged in user when an api call is made:
$this->get('security.context')->getToken()->getUser()
returns anon. that stands for anonymous, or
$this->getUser();
returns just null.
So the authenticated context seems to be gone when using the rest api. However when I call an action directly without rest, I can get user information.
So what we need is to secure our rest api and get user information on every api call. We don't want third party people to access our application, just staff. I am not familar with OAuth, but the user will be redirected to a third party page to Allow/Deny access to his data? This would not be an option for us.
Based on that information, do you have any suggestions or ideas how to secure the api and transport the user data so that getUser does not return null or anon. but the actuall logged in user?
there's another way to resolve your problem.
It's by using Certificates.
you can generate certificates then use Http tunneling (https obviousley), the server will ask for a certificate (you've to configure Apache for that but it's not a big challenge).
with this in place, you've to add a CertificateManageron the server side to ensure that the certificate is valid and to know who's calling the service (to be able to authenticate the user at each request), the CertificateManager(or what ever you'll call it) will probably have to be configured within you filters chaine (as known in the java world), et voilà
Hop that help you,
Abderrazak
REST is stateless so you will have to send some kind of authentication/authorization in each request. You can use HTTP BASIC AUTH or something like OAuth.
Have a look at https://github.com/FriendsOfSymfony/FOSOAuthServerBundle
I'm kind of building our application in exactly the same architecture (RESTful API with Symfony2 back-end and AngularJS frontend.
Another way is to duplicate the api routes, so that you have the api routes protected by OAUTH and the api routes protected by the session, both of them pointing to the same controllers. The method was explained here: https://stackoverflow.com/a/22964736/435026