Google Smart Lock vs Credential Management API - google-signin

I want to implement frictionless sign in process for my web app.
After some searching, I have found that there are two solutions available :
Google Smart Lock.
Credential Managment API.
My question is, What is the difference between the two API's (if any) and what are the possible use cases for both of these.
From what I have understood, both allow us to save account related info. But the advantage with smart lock is, that saved credentials can be used in corresponding android apps as well.
Thanks !
Note:
I intend to support login from multiple sources (google, facebook, linkedin etc.) , not just google.

TL;DR the one-tap sign-up / auto sign-in library includes Credential Management. You should probably just use the library: https://developers.google.com/identity/one-tap/web/get-started
Details
The JavaScript library supports account creation with Google Accounts (via a streamlined inline UX that can be shown on content pages instead user having to navigate to a traditional button-based UX and figure out which which button/option to pick and interact with pop-up/redirect)
And for returning users, the library allows you to programmatically retrieve on page load both tokens for existing one-tap / traditional Google Sign-In users as well as passwords via the Credential Management API in browsers that support it. You can do this with code such as the following:
const retrievePromise = googleyolo.retrieve({
supportedAuthMethods: [
"https://accounts.google.com",
"googleyolo://id-and-password"
],
supportedIdTokenProviders: [
{
uri: "https://accounts.google.com",
clientId: "YOUR_GOOGLE_CLIENT_ID"
}
]
});
retrievePromise.then((credential) => {
if (credential.password) {
// An ID (usually email address) and password credential was retrieved.
// Sign in to your backend using the password.
signInWithEmailAndPassword(credential.id, credential.password);
} else {
// A Google Account is retrieved. Since Google supports ID token responses,
// you can use the token to sign in instead of initiating the Google sign-in
// flow.
useGoogleIdTokenForAuth(credential.idToken);
}
}
See the documentation for details. The library does not currently support non-Google/password forms of identity, you'd have to implement sign-in flow with other mentioned identity providers SDKs yourself at the moment.
Also note that any sign-ins associated with a Google Account (OAuth token-based or stored and sync'ed password) will be available across Android and Chrome (and the rest of the for token-based accounts).
Please leave comments for any follow up questions.

Related

Does google identity platform supports LinkedIn out of the box like it does for Facebook or Gmail

I am trying to use google identity platform for my application by following the below link
Google Identity Platfrom
But on this page, no identity provider mentioned for LinkedIn and same is not searchable on web.
What I understood is Google's Identity platform is using Firebase underneath. I am just wondering, on Firebase portal it is mentioned that a custom implementation is required for LinkedIn whereas under the GCP account -> Add provider I can see LinkedIn.
What I would like to know is, if it is possible to add LinkedIn as provider out of the box under identity platform.
You can use LinkedIn.com provider directly via Identity Platform without using custom authentication. It is the same as using a generic OAuth provider like Microsoft or any other provider. Here is an web example:
const provider = new firebase.auth.OAuthProvider('linkedin.com');
firebase.auth().signInWithPopup(provider)
.then((userCredential) => {
// User signed in.
})
.catch((error) => {
// Error signing in.
});
However, this is currently not yet available in Firebase.

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.

Is there any way to programmatically authenticate customers in Shopify?

We have a custom app hosted in Firebase (Google's Backend as a service). We would like to use Shopify's authentication so the user doesn't have to create an account in the app as well as the Shopify store (where we require accounts).
The key: I need to have some mechanism (like an API) that I can use to have Shopify authenticate a user. (Assume the customer has already created an account in the Shopify store. Account creation will be handled by the normal Shopify process.)
I can create a page in my app to ask for email / pass. Is there some way to send this info (perhaps along with some sort of token generated from a private app) to authenticate the customer? I just need Shopify to confirm whether the email / pass is correct, so I can then 'login' the user into my Firebase app.
Any direction / thoughts / suggestions are greatly appreciated.
PS. Firebase offers a 'custom authentication' option, along with email, Google+, Facebook. The custom auth option requires sending user / pass to the authentication server, which in this case, would be Shopify.
EDIT: Based on the responses, edited to clarify that I need some way to authenticate the user in Shopify. Handling the custom auth into Firebase seems like a fairly straightforward task, once I receive some sort of signal from Shopify telling me the users email / pass is valid.
This is a classic use case for custom Auth with Firebase. You send email/pass to your backend, authenticate with shopify, on success create a custom token with the user's id (most likely using shopify's user id), send it back to the client which would signInWithCustomToken signing in to Firebase.
Customer logs in to Shopify
Logged in Customer has an ID
Use App Proxy in your App to accept this ID using a secure callback
Use the Shopify API to look up the customer with the secure ID
If customer is found, they are then authentic and can use your App
Why is that not a useful and simple pattern for you to use?
You should take a look to Shopify MultiPass. Although, you need Shopify Plus that is very expensive.

G Suite identity provider for an AWS driven browser based App

I'm aware of how to create a Google authenticated app via with google-signin-client_id 3089273xx-xxxxxxxxxxxx.apps.googleusercontent.com & <script src="https://apis.google.com/js/platform.js" async defer></script>, but the problem here is that, I have not been able to LIMIT the login to just my company's G Suite instance.
The app I have is a "serverless" JS bundle hosted on S3. The logged in Google token is tied to an AWS role that accesses sensitive resources.
So typical solutions to check the email of googleUser.getBasicProfile() or pass a hd parameter don't make any security sense since they can be manipulated with browser dev tools IIUC.
Is there some other Google API I could be using or strategy I could apply? I imagine the solution would come in the form of a special google-signin-client_id for my company's domain which is hosted by G Suite. This is how it's tied to the role at AWS:
I'm aware I could setup duplicate my users in AWS "user pools" and use Cognito, but I am trying to have a "single source of truth" for the company's employees & ease the administration burden.
UPDATE: This answer is insecure as if you simply remove hosted_domain, you can authenticate with any Google login.
After straying upon https://developers.google.com/identity/work/it-apps & using GAPI directly I found I could do a
GAPI.auth2.init({
client_id: CLIENT_ID,
hosted_domain: 'example.com'
})
And then as the documentation advises, you setup Manage API client access
So now only users of #example.com on Gsuite can access this JS app! This took weeks to figure out. So just to conclude, how to authenticate using Google on a AWS powered serverless app:
Setup a client ID via OAuth client ID with your whitelisted origin URLs from https://console.developers.google.com/apis/credentials
In AWS IAM setup a Role with Google as the (web) Identity provider with the client ID
Add your client ID https://admin.google.com/AdminHome?chromeless=1#OGX:ManageOauthClients as documented here https://developers.google.com/identity/work/it-apps to crucially limit your application to your company's domain.
So now we have a statically hosted App limited to only company employees to access sensitive paid AWS APIs.
I tried 3 different options, the first one worked for my scenario:
First Option - Validating Google Id Token on each call on lambda side
I always pass the id_token as a header on the client calls(web and mobile apps).
"acceptableHds" Is the list of allowed domains.
const oauth = new Auth.OAuth2(CLIENT_ID_WEB, CLIENT_SECRET);
oauth.verifyIdToken(token, null, (err, ticket) => {
if (err) {
return reject(err);
}
const payload = ticket.getPayload();
const tokenIsOK = payload &&
payload.aud === CLIENT_ID &&
new Date(payload.exp * 1000) > new Date() &&
acceptableISSs.has(payload.iss) &&
acceptableHds.has(payload.hd)
return tokenIsOK ? resolve(payload.hd) : reject();
});
Second Option - Validating Google Id Token once on lambda side
I started this alternative way but I didn't finished because the first solutions fitted to my needs and the milestones was close(it needs a indentity pool):
1)Send the id_token to the lambda function and validate it on Google API(here is where you can check the domain using the code above)
2)Call the cognitoidentity.getOpenIdTokenForDeveloperIdentity on the lambda side using the id_token coming from the browser
3) On the client, call any of the Cognito or STS functions like assumeWebIdentity, AssumeRole using the tokens returned from getOpenIdToken.
function getCognitoToken(id_token) {
var param = {
IdentityPoolId: 'us-east-1:f7b3d55f-6b63-4097-be8f-3dc22ddec1a4',
Logins: { 'accounts.google.com': id_token }
}
return check_company(id_token).then(function (valid) {
return cognitoidentity.getOpenIdTokenForDeveloperIdentity(param).promise()
})
I couldn't finish the third step. You need use the tokens received on the second step without revealing the 'identity pool id'. If you do that and assure that the role can't list identity pool ids, it will work as intended and It will be secure.
Third Option - SAML provider
You can create a SAML provider and use SAML assertions to validate the user domain.
http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml_assertions.html
I failed miserably trying to do it.
P.S.: Google Admin let you create private apps, limiting to you company domains, but It works only for mobile as far as I know
https://support.google.com/a/answer/2494992?hl=en
Hope it helps someone!

Check if user has my Facebook app installed

My website uses a Facebook application which sends notifications to its users.
On one of my pages the user can subscribe or unsubscribe (depending on whether or not he is subscribed).
Therefore I want to check if the user is using my app. How can I do that? I guess I could do the following to see if the app can access the data:
FacebookClient c = new FacebookClient(accessTokenClaim.Value);
c.AppId = MYAPPID;
c.AppSecret = MYAPPSECRET;
dynamic access = c.Get("/me/permissions");
if(access != null)
{
//has access
}
The one thing I don't like about this, however, is the fact that I have to use an access token to see if the user has the app installed.
I would prefer not to use access tokens since they tend to expire.
In my database I store the Facebook userIds of all my website users.
Therefore it would be ideal if I could do something like the following:
/get?appinstalled&userid=USERID
What would be the best way to go about this?
To get the current user ID - to compare it with your DB - you will have to access FB graph API using an access token. So I think there is no way to find any info about the user without using FB access tokens.
Edit: And do not worry about the expiration of the token, FB SDK will handle that for you. i.e. it will refresh automatically by the SDK. Here:
Facebook's official SDKs manage the lifetime of tokens for you. When
using iOS, Android or our JavaScript SDK, the SDK will handle making
sure that tokens are refreshed before they expire.
And
Access tokens on the web often have a lifetime of about two hours, but
will automatically be refreshed when required. If you want to use
access tokens for longer-lived web apps, especially server side, you
need to generate a long-lived token. A long-lived token generally
lasts about 60 days.

Resources