get account profile after logging in? - meteor

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)

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?

Have one user signup another user with custom fields in firebase/flutter

I am trying to determine if the following scenario is possible with flutter and firebase:
we have users within the company who will be given access to the app, where on the homepage will be a signup another user button where they enter in that user's email and password, they get signed up, and then the original user specifies custom fields for the 2nd user, such as company name, role, position, etc.
Is this possible with flutter and firebase?
Have asked the flutter google group and was told about custom authentications, but from what I see that is just an external authentication system and doesn't show me how to let one user create another users profile with fields.
Any ideas?
The first thing to consider is whether those properties need to be in the user profile at all. The user profile is sent with every request, and should only contain information that is relevant for securing access. If you have additional information to store about the user, you should store it elsewhere (such as in one of Firebase's databases) using the UID of each user as its key.
Assuming that the information is about security (such as the role seems to be, there is no secure way to let one user set security properties (typically referred to as claims) from client-side code. As soon as this is allowed from client-side code, anyone could set such properties for anyone else. That's why setting custom claims for a user is only possible with Firebase's Admin SDKs, which are designed to run in a trusted environment - such as your development machine, a server you control, or Cloud Functions.
There are a few other options, but it's important to realize they're all implemented on top of the above approach.
There is an experimental extension that allows you to set auth claims by writing a document into Firestore, which something like this (JavaScript syntax, but the Flutter code will be similar):
db.collection("user_claims")
.doc("abc123")
.set({
role: "admin",
groups: ["example1", "example2"],
});
Now of course you'll want to make sure that you secure writing to the user_claims collection, as otherwise you'll end up with the same security risk I mentioned in the first paragraph, where everyone can claim any role they want.
Alternatively you can write your own server-side API (for example on Cloud Functions) that you expose to your application, and that then calls the Admin SDK. Here too, it is important to secure access to this API, to ensure only authorized users can call it.

How to prove to the server that I as a client am logged in with the given uid?

Heres my problem:
I wan't to be able to create new users for my website, from my website. This is only aloud though, if I have the "isAdmin" flag set to true in the realtime db under /users/myid.
Generally I would have done this with a security rule but the problem here is that I need to use the admin SDK, since the normal "createNewUser" method signs in to the newly created user automatically. I as an admin though, want to be able to create a new user and stay logged in as myself. So what I wan't to do is use ajax post request to my server with my uid und the new userdata which is to be created. My server then checks if the given uid has the isAdmin flag and if so creates the user with the firebase admin SDK which provides such a method.
But, anyone, if they have an admins uid, could hit up that request and create a new user. (My clients definetely get uid's from other users).
So how would I go about proving to the server that I am actually logged in with that uid.
From my understanding, tokens are used to be able to write to the database, but I don't need that permission, I just need to prove that I'm actually logged in with that uid.
Is there something I'm missing? Thanks a lot guys!
Was easier then I thought. This will generate a token on the client side:
firebase.auth().currentUser.getToken(true).then(function(token) {
// send request to server with generated token
}).catch(function(error) {
// handle error
});
Which I can then verify on the server like so:
admin.auth().verifyIdToken(idToken)
.then(function(decodedToken) {
var uid = decodedToken.uid;
// user is logged in
}).catch(function(error) {
// user is not logged in, or other error occured
});
Taken from https://firebase.google.com/docs/auth/admin/verify-id-tokens

How make a secure login via LinkedIn sign in button

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.

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