How make a secure login via LinkedIn sign in button - linkedin

I wanted to implement a LinkedIn sign in button and came across with below URL with a simple guide how to implement it.
https://developer.linkedin.com/documents/sign-linkedin
<script type="text/javascript">
function onLinkedInAuth() {
IN.API.Profile("me")
.result( function(me) {
var id = me.values[0].id;
// AJAX call to pass back id to your server
});
}
</script>
From the guideline given, it mentioned that after user has successfully signed in to their linked in account a JS callback function can be executed and profile details of the user can be retrieved.
It did mentioned as well that basically you can pass the linkedin id of the user to the server and it can be used to identify the user and eventually authenticate.
For this method, i find it less secure since anyone can probably get someone else linked in ID. How do you guys enhance the login flow to make it secure?
I really appreciate any input.
Thanks!

Even if someone was able to retrieve the ID, it would be useless to them.
User IDs via the API are different from the IDs you see on the linkedin website, as they differ from application to another. So even if the user had access to the ID, they will still need to have access to your application's keys (Consumer key and Consumer secret)
I hope this helps.

Related

Furnishing user data in NextAuth EmailProvider and Fauna DB on signIn

I'm using NextAuth's EmailProvider and FaunaAdapter with a FaunaDB instance to authenticate users in my NextJS application. I'm going down the "passwordless" route with this site, and the magic links are setup nicely after finishing the bulk of this tutorial.
There are some changes I've made to it, however, as I don't want a Sign Up page, and instead want only whitelisted emails that exist in my DB to be sent links to authenticate. I've done this by hijacking the signIn callback like so:
async signIn ({ user, account, profile, email, credentials }) {
// As "signIn" gets called twice when using magic links (once for sending and once for authenticating),
// we need to check here if this is a request for a magic link, as opposed to authenticating a token.
if (email.verificationRequest) {
// This is a helper function which does a lookup for the email in the "accounts"
// table of my Fauna DB.
return checkUserEmailExistsInAccounts(account.userId)
}
return true
}
This works nicely, but I wonder if it could be improved. I want any page that is behind the authentication wall to effectively have a session or JWT token that describes the user in more detail. If, say, I want the user name to be added to the session data, I then need to somehow modify the session or jwt callbacks to add this data. But that will involve yet another call to the database, where I have already made a perfectly useful call in the signIn process. Whats more, these callbacks are made frequently - whereas the signIn callback is only made a couple of times during the authentication process.
To summarise: how can I leverage a magic link sign-in system with NextAuth where I look up allowed emails from a pre-existing Fauna accounts collection, furnish a user object with the account data and have the account data become available to every page without needing further lookups when already-authenticated?
Edit: Just a note to say that when I first started playing with the library, I was surprised that simply putting the data into my accounts collection in Fauna DB didn't somehow magically make it appear in the session info. Perhaps I am not using the Fauna Adapter correctly, and this is actually the better way to go?

Firebase Auth on Web - How to add spam protection for email/password login

For my website, I want to build my own login form for email/password based authentication using Firebase authentication instead of using FirebaseUI Web. I'll be using createUserWithEmailAndPassword JS function to create new user accounts. But how can I prevent spam registrations? Usually for web based forms, I would use Google Recaptcha and validate the recaptcha on my server. But here, I'm not using my server for creating the user accounts. I'm making a call on the client side to create the user accounts.
Of course, I'll be using email verification in the flow, but how would I prevent bots from creating the accounts in the first place?
I also understand that Firebase has some sort of limit for the number of requests per min from a single IP, but I would like to go further and try to prevent those registrations.
firebase.auth().createUserWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
Thanks.
After 2 years, this question is still valid and as far as I see, it is not possible. You probably do not need an answer to this question anymore but it may help others. Even if you succeed in doing something manually, those js functions will stay there and can be called manually by any user who knows how to do it.
If there are no hidden, top secret options which are not available in the documentation, this is not possible. There is a recaptcha option but it is only for Phone Authentication. So, it seems like you have 2 options.
Ignore and delete users who do not verify their email address.
Disable email option from Firebase console and implement your own
email authentication. Generate your own token and log user into
Firebase with that custom token. https://firebase.google.com/docs/auth/web/custom-auth
I'm following up on frankish's answer. He is totally correct, and I agree I think it's strange that Firebase automatically integrates ReCaptcha when doing phone authentication (and now when doing Phone MFA), but does not provide support in createUserWithEmailAndPassword for passing a recaptcha verifier. Thus, the only way to really get around this is to do something like the following:
Set up ReCaptcha (either V2 or V3) manually on your signup page. Do NOT use firebase. auth. RecaptchaVerifier, that is only for integration with phone authentication.
Immediately after calling createUserWithEmailAndPassword, you need to make a call to your own server that passes up the recaptcha token. There is a Firebase blog post here about how to do that with a Firebase Function: https://firebase.googleblog.com/2017/08/guard-your-web-content-from-abuse-with.html. Note I think it's a bit strange that Firebase documented how to do this with server-side functions but didn't directly integrate this with account creation.
The final point is that in your server-side code, after you make the call to validate the recaptcha token, you need to set a custom claim on the Firebase user with the Firebase Admin API. That claim can be something like recaptchaPassed: true (or false). For details on custom claims see https://firebase.google.com/docs/auth/admin/custom-claims.
After that, you can then do things based on the value of that custom claim. For example you could read that custom claim in other server-side calls, or you can use it in Firestore security rules (good blog post on this, https://medium.com/google-developers/controlling-data-access-using-firebase-auth-custom-claims-88b3c2c9352a). You could also choose to immediately delete the user server-side (using the admin API), if recaptcha verification fails.
Note it's important to understand that there is nothing that guarantees that some malicious script will call your server-side token verification function after the code on the client calls createUserWithEmailAndPassword. Thus, the only way the rest of your code can guarantee that a particular Firebase user passed recaptcha verification is by looking for your custom claim that you set on the user server-side.

How to get Google Sign-In for Websites to work with Identity Aware Proxy

I have a web site in google cloud. I use Identity-Aware Proxy (IAP) to protect it.
When a request comes in IAP checks if I'm authorized and then responds with either
if I'm authorized: the response from the resource I requested
if not: a 302 or 401 response depending on if it thinks it is an ajax call or not
Now I want to use Google Sign-In for Websites on top of this.
This might seem redundant since I am already logged in by the time I would see the buttons but I want to use it as a way to log out or change user account.
Now what I have tried to do is:
var auth2 = gapi.auth2.init({
client_id: 'mykey.apps.googleusercontent.com',
})
auth2.isSignedIn.get()
// false, I was hoping that I could somehow piggyback on my existing session
auth2.signIn()
// shows a pop up, allowing me to select an account
auth2.isSignedIn.get()
// true
currentUser.getBasicProfile()
// works
This seems to work except it shows me a login box even when I'm already logged in which is suspicious.
Add to this that when I do
auth2.disconnect()
auth2.isSignedIn.get()
// false
and then do a full refresh then I still get my resources from IAP proving that I'm still logged in there.
Questions:
How can I get this to work?
Is this even the correct way to do it?
I don't know much about Sign-In for Websites, but there's another option that might work for you. Have you considered adding a link to /_gcp_iap/clear_login_cookie to provide a "change user account" option? (It's documented here: https://cloud.google.com/iap/docs/special-urls-howto )
If the user is logged in with multiple Google accounts, that will bounce them back to the account picker. Today, if they're only logged in with one account, it will just send them right back into the application -- but there's an enhancement rolling out next week which will display the account picker even for the single-account case, giving the user a chance to sign in with an additional account.
Hope that helps!
--Matthew, IAP engineering lead

get account profile after logging in?

is it possible to get the user profile pic after the user has signedup and then signed in using meteor accounts. I tried querying
Meteor.user().services.google
or
Meteor.user().services.facebook
but I Meteor.user().services comes out as undefined. So I'm not quite sure how to access the profile pic.
Note I don't want to rewrite the signup process and Accounts.onCreateUser it would be much easier to simply add in user details after a user logs in.
There are two options but the best would be to write Accounts.onLogin because there is a security reason you can't access it with Meteor.user().services.
The stuff inside Meteor.user().services is sensitive, it contains the OAuth keys, your Meteor access tokens and your password hashes, this is why its blocked from access to the client. Its a very short CSF attack to stealing your account (and possibly get access to your facebook, google+, twitter, etc)
You can make it 'open'
Server side code
Meteor.publish("userdata", function() {
return Meteor.users.find({_id: this.userId});
});
Client side code
Meteor.subscribe("userdata")
More Secure Way
The more secure way would be to create the onLogin/onCreate callback, grab their profile picture url/other profile data and put it in profile and not have any publish functions like the one above
In your onLogin callback
var avatar = .. get your avatar url for whatever service you're using
//Assuming you've called the onLogin callback parameter 'info'
Meteor.users.update({_id: info.user._id}, {$set:{'profile.avatar':avatar}});
Then you can just do this when you need their profile pic
<img src="{{currentUser.profile.avatar}}"/>
This way you could do the same for the other data too! And standardize it in a way that works accross multiple services (facebook, google+, twitter, etc)

Limit Meteor.js built-in Google authentication to a domain

I'd like to use the Meteor.loginWithGoogle() tool to authenticate users, but is there any way to limit it to a specific (Google Apps) domain?
I could check after the user is authenticated using the returned email, but is there a way to do this at the login stage with some parameter for Google login?
I dont think its possible right now.
There is a pull resquest to partly add that functionality: https://github.com/meteor/meteor/pull/1332
The issue with that pull request seems to be that it only fixes the client side of thinges (ie. it only shows accounts from the selected domain when the user logs in).
But it does not add any server side checks.
Im using the following workaround:
In a .js file in the sever folder I have the following code:
Accounts.validateNewUser(function (user) {
if(user.services.google.email.match(/example\.org$/)) {
return true;
}
throw new Meteor.Error(403, "You must sign in using a example.org account");
});
This prevents accounts from being made for domains different from example.org.
If you want to only allow certain users from your domain, you could also add a whitelist collection that defines user ids from your Google Apps account. This way you can restrict access to only certain users, get single sign-on functionality, and can pre-set user roles and properties for your app before users even create their accounts.
Use the Accounts.onCreateUser(function(options, user){}) callback for that since it allows you to define additional user properties.

Resources