Why can't we use getUid() to authenticate with your backend server in firebase authentication - firebase-authentication

In this code snippet (firebase doc) they have mentioned do not use user.getUid() to authenticate with your backend server. use FirebaseUser.getToken() instead.
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user != null) {
// Name, email address, and profile photo Url
String name = user.getDisplayName();
String email = user.getEmail();
Uri photoUrl = user.getPhotoUrl();
// The user's ID, unique to the Firebase project. Do NOT use this value to
// authenticate with your backend server, if you have one. Use
// FirebaseUser.getToken() instead.
String uid = user.getUid();
}
getUid() // A unique user ID, intended as the user's unique key across all providers.
getToken() // The Firebase authentication token for this session.
My requirement is.
First I will register user with firebase authentication method (Email and password).
I will save String uid = user.getUid(); in my own backend server once registration is successful.
User credit information say user balance is saved in my own backend server as key user.getUid().
User sign-in with Email and password and ask for his balance.
I will get user.getUid() from firebase and match with my records, if match found returns balance to user.
They said getUid() is unique user id but Do NOT use this value to authenticate with your backend server.
Why so? Why can't we use getUid() to authenticate with your backend server??

The uid is a unique identifier for the user. So, while it identifies the user, it does not authenticate them.
A simple corollary is that my Stack Overflow ID is 209103. Knowing that, you can identify me. But to prove to Stack Overflow that you are Frank van Puffelen, requires that you know my credentials.
The ID of a user is quite often exposed in the interface. For example, if you click on my profile, you will see my ID. This is necessary for identifying me. If you would also use that same ID to authenticate, everyone who had seen your profile once could impersonate you on the site. Not a good idea when it comes to security.

Take your requirements as an example, if you using [GET] https://your-domain.com/api/users/$uid/balance to retrieve user's data, then this API is not secured at all, anybody could get other user's data with a random $uid.
As the comment(firebase doc) recommends, FirebaseUser.getToken() will get a JWT token, you should validate the token with firebase Admin SDK in your backend, and that is the data you could trust.
And the method client-side method should update to user.getIdToken() by now.
https://firebase.google.com/docs/auth/admin/verify-id-tokens is the reference for more detail.

Related

Strapi, use Auth0 to access user data in Strapi

I have a React Native app that uses Strapi for its main API.
Some of the API endpoints require authentication so I've used the Auth0 provider and that's all working fine.
A user is now able to log in and I'm securely storing their access_tokens.
So far, Auth0 only gives me an access_token, a refresh_token, an id_token (jwt containing name and email etc) and expiry times for the tokens.
But I'm wondering if it's possible to be able to store a users preferences like whether they prefer dark or light theme etc and extra info such as a user_id in Strapi and let them update it after logging in with Auth0.
The catch is that only that user should have read/write access to their own data.
I can't see any docs or guidance on this kind of thing. Has anyone else managed to implement this kind of thing and if so, a rough approach would be great!
Thanks!
Well, one way of the doing this is creating a OAuthUsers collection in strapi, which will hold basic details of a user like:
first_name
last_name
email
When a user registers on Auth0 and returns back to your site, you can take the basic details that were returned from the identity management platform and store it in strapi under the OAuthUsers collection.
Now, coming to your question on how to store the preferences of the user, what you can do is create another collection called preferences with following attributes:
is_dark_theme
OAuthUser (Make this a one-to-one relation with OAuthUsers collection )
Every time a logged in user updates his preferences it will first come and create an entry in this collection if not already existing. How you can check if an entry exists for a user is by using the email from the JWT token itself, that you attach as the bearer token on the API calls. I will assume, you already know how to decode a JWT token.
So a rudimentary design would be like so:
const is_dark_theme = request.body.is_dark_theme; // 1 or 0 for light theme
const user = await strapi.services.OAuthUsers.find({ email: '[email from JWT]'});
const preference = await strapi.services.preferences.find({ OAuthUser: user.id });
if(preference)
await strapi.services.preferences.update({is_dark_theme}, {id: preference.id});
else
await strapi.services.preferences.create({is_dark_theme, user: user.id});
So per this, what will happen is the user will only be able to update his own details and never be able to touch the preferences of other users as the user will only be able to pass the is_dark_theme parameter from front end and rest of the information will be taken from the JWT token.

OneLogin - Get logged in user's ID

I need to get logged in user's ID on a web page where user is authenticated via OneLogin. We need to use OneLogin's REST API endpoint that can give me logged in user's details.
https://api.domainname.onelogin.com/api/1/users/:id
For above REST API I need user's ID.
Can you please help me figure this out?
Are you saying the user has a OneLogin session? Or that you are using the API to authenticate the user using the delegated authentication API?
If you are using this: https://developers.onelogin.com/api-docs/1/users/create-session-login-token
The user ID is in the response.
If the application you're writing supports SAML then part of the SAML assertion you got from OneLogin should be a unique user attribute (email or username)
Your best bet is then to get that user from OneLogin by using that attribute -
https://api.<us_or_eu>.onelogin.com/api/1/users?email=user#test.com
or
https://api.<us_or_eu>.onelogin.com/api/1/users?username=testuser
And since that value is unique, it will only return the one matching record (i.e. The current user)

How to link different authentication providers in azure mobile services

What is the best practice in azure mobile services to use different authentication providers (Facebook, Google, Windows e.t.c.) and understand that this three logins belong to the same user.
Out of the box if a user1 choose to use Facebook for authentication on his mobile phone and add some information to the app, and later he (user1) try to login with Google on his tablet, he will not see his information. Because they are two different users with different tokens. And I want to take some additional information from authentication providers (email) and has my own user table which contains email and other profile info shared for user no matter what provider he uses. How could I achieve it?
P.S. I use .NET as a backend and Windows Phone as a client
There isn't an out-of-the-box solution here. You would probably be best served by using a lookup table which maps a static user ID that you define to different identity provider IDs. Then, everywhere that you take a dependency on the user ID, you would do a lookup to match the current user identity to your static identifier. Your user ID is what gets stored everywhere else in the database.
The important detail here is that a Mobile Services token maps to a single provider identity. If you look at the user ID, it is actually provider:providerID. So we need to obtain two tokens and validate both together in order to associate two IDs.
On the client, you would have to manually prompt the user to link accounts. You would stash the current token in memory during this process, log in with the new provider, then call and API on the backend which does the association.
string existingToken = App.MobileService.CurrentUser.MobileServiceAuthenticationToken;
App.MobileService.Logout(); // allows login with new provider
await App.MobileService.LoginAsync("google");
await App.MobileService.InvokeApiAsync("associateToken", existingToken);
On the server, you need to be able to validate existingToken (the new one being implicitly validated by restricting the API to AuthorizationLevel.User)
Within that API, you can validate the token using:
IServiceTokenHandler handler = this.Request.GetConfiguration().DependencyResolver.GetServiceTokenHandler()
ClaimsPrincipal claimsPrincipal;
bool didValidate = handler.TryValidateLoginToken(existingToken, ConfigurationManager.AppSettings["MS_MasterKey"], claimsPrincipal);
You should probably also look up the user ID in your lookup table to avoid conflicts.
So overall that's a rough sketch of a possible solution. Unfortunately there isn't anything more turnkey.

What is the unique information on google plus login

I managed to login with google plus, but after authenticating, I'm not sure which of the values is the unique value to authenticate the user.
After authenticating, I see a response with fields like:
access_token, code, id_token, but I'm not sure which to use?
access_token: you use this to make API calls as the user who has just signed in - e.g. to retrieve profile information. This is valid for 1 hour.
id_token: this is a special signed blob which contains the user id of the signed in user, and the client ID of you application, can be used to identify the user. This is valid for one hour also.
code: you can send this to a server to exchange for an access token (to allow the server to make calls). This is valid for a few minutes.
In general you will use the access token to retrieve the user's name and photo as a next step: https://developers.google.com/+/web/people/#retrieve_profile_information

How to identify a Google OAuth2 user?

I used Facebook login to identify users. When a new user comes, I store their userID in my database. Next time they come, I recognized their Facebook ID and I know which user it is in my database.
Now I am trying to do the same with Google's OAuth2, but how can I recognize the users?
Google sends me several codes and tokens (access_token, id_token, refresh_token), however none of them are constant. Meaning if I log out and log back in 2 minutes later, all 3 values have changed. How can I uniquely identify the user?
I am using their PHP client library: https://code.google.com/p/google-api-php-client/
As others have mentioned, you can send a GET to https://www.googleapis.com/oauth2/v3/userinfo, using the OAuth2 bearer token you just received, and you will get a response with some information about the user (id, name, etc.).
It's also worth mentioning that Google implements OpenID Connect and that this user info endpoint is just one part of it.
OpenID Connect is an authentication layer on top of OAuth2. When exchanging a authorization code at Google's token endpoint, you get an access token (the access_token parameter) as well as an OpenID Connect ID token (the id_token parameter).
Both these tokens are JWT (JSON Web Token, https://datatracker.ietf.org/doc/html/draft-ietf-oauth-json-web-token).
If you decode them, you'll get some assertions, including the id of the user. If you link this ID to a user in your DB, you can immediately identify them without having to do an extra userinfo GET (saves time).
As mentioned in the comments, these tokens are signed with Google's private key and you may want to verify the signature using Google's public key (https://www.googleapis.com/oauth2/v3/certs) to make sure they are authentic.
You can see what's in a JWT by pasting it at https://jwt.io/ (scroll down for the JWT debugger). The assertions look something like:
{
"iss":"accounts.google.com",
"id":"1625346125341653",
"cid":"8932346534566-hoaf42fgdfgie1lm5nnl5675g7f167ovk8.apps.googleusercontent.com",
"aud":"8932346534566-hoaf42fgdfgie1lm5nnl5675g7f167ovk8.apps.googleusercontent.com",
"token_hash":"WQfLjdG1mDJHgJutmkjhKDCdA",
"iat":1567923785,
"exp":1350926995
}
There are also libraries for various programming languages to programatically decode JWTs.
PS: to get an up to date list of URLs and features supported by Google's OpenID Connect provider you can check that URL: https://accounts.google.com/.well-known/openid-configuration.
I inserted this method into google-api-php-client/src/apiClient.php:
public function getUserInfo()
{
$req = new apiHttpRequest('https://www.googleapis.com/oauth2/v1/userinfo');
// XXX error handling missing, this is just a rough draft
$req = $this->auth->sign($req);
$resp = $this->io->makeRequest($req)->getResponseBody();
return json_decode($resp, 1);
}
Now I can call:
$client->setAccessToken($_SESSION[ 'token' ]);
$userinfo = $client->getUserInfo();
It returns an array like this (plus e-mail if that scope has been requested):
Array
(
[id] => 1045636599999999999
[name] => Tim Strehle
[given_name] => Tim
[family_name] => Strehle
[locale] => de
)
The solution originated from this thread: https://groups.google.com/forum/#!msg/google-api-php-client/o1BRsQ9NvUQ/xa532MxegFIJ
It should be mentioned, that the OpenID Connect API returns no id attribute anymore.
It's now the sub attribute which serves as a unique user identification.
See Google Dev OpenID Connect UserInfo
"Who is this?" is essentially a service; you have to request access to it as a scope and then make a request to the Google profile resource server to get the identity. See OAuth 2.0 for Login for the details.
Altough JWTs can be validated locally with the public key, (Google APIs Client Library downloads and caches they public keys automatically) checking the token on Google's side via the https://www.googleapis.com/oauth2/v1/tokeninfo endpoint is necessary to check if the access for the applicaton has been revoked since the creation of the token.
Java version
OAuth2Sample.java