AWS Cognito Missing required key 'DeviceKey' in params - javascript

Hi doing my user management using the so useful Amazon web service Cognito.
I would remember my users devices on login but when I'm calling the
cognitoUser.setDeviceStatusRemembered()
I have this error message :
Missing required key 'DeviceKey' in params
This is how I have implement it:
AuthService.login($scope.username.toLowerCase(), $scope.password)
.then(function(res) {
if ($scope.rememberMe == true)
AuthService.setRememberedDevice($scope.username);
})
My login function is well working for a long time.
I have read on this question :
AWS Cognito Identity JS: Forget/Remember/Do Not Remember Device
...that a call to the getCachedDeviceKeyAndPassword() could solve this problem but I can not figure out where to find an implementation of this method or how to use it.
I think #Ionut Trestian could know the right answer

Which enviornment are you running? If you run it in a browser, the tokens and device keys are stored in local storage, and if you run it in a server side enviornment, they are stored in memory.

I'm not sure which SDK/library you are using. With the current Amplify library, you can get the device key through the user object:
Auth.currentAuthenticatedUser({
}).then(user => {
user.getCachedDeviceKeyAndPassword(); // without this line, the deviceKey is null
console.log(user.deviceKey);
});

Related

Firebase HTTPS callable function context.auth is always null when used with custom token auth

HTTPS callable function is called directly from our app after signing in using custom token (custom auth), but context.auth is null in function eventually.
I am wondering if this is something expected? I am not providing any specific example (our client is using Firebase SDK with Kotlin, everything is implemented accordingly to the example in docs), just want to know if maybe someone had similar issue or maybe we need to double check our client's code (custom token authentication is actually working there, since we use firestore with security rules that require it).
I was trying to find some information about certain restrictions, but there's none: Firebase FAQ https://firebase.google.com/support/troubleshooter/functions/auth/callable (nothing about custom token), this answer here Do I need to use verifyIdToken on the context.auth object in firebase cloud functions?
Been asked to add an example of the cloud function, nothing specific, is reproducible with simple one like the following (auth will be always null in log record):
exports.getData = functions.https.onCall((data, context) => {
functions.logger.info('Auth info', { auth: context.auth });
return {
success: true,
data: null,
};
});
Seems like a potential race condition, Ensure that Auth has created the user object before requesting the callable function if you are calling it directly after a sign-in method.
This can be done using a callback from an onAuthStateChanged.
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
Source: https://firebase.google.com/docs/auth/web/manage-users#get_the_currently_signed-in_user

Google SignIn SDK is failing by throwing error, A non-recoverable sign in failure occurred -catch error: React Native

I have been trying to integrate Social login in my react native project in which I was able to do facebook login successfully but it is failing to signin to google. react-native-google-signin library is used for google.
The code I have used.
componentDidMount() {
GoogleSignin.hasPlayServices({ autoResolve: true }).then(() => {
// play services are available. can now configure library
}).catch((err) => {
console.log("Play services error", err.code, err.message);
})
GoogleSignin.configure({
scopes: ["https://www.googleapis.com/auth/drive.readonly"], // what API you want to access on behalf of the user, default is email and profile
// iosClientId: <FROM DEVELOPER CONSOLE>, // only for iOS
webClientId: "xxx", // client ID of type WEB for your server (needed to verify user ID and offline access)
// offlineAccess: true // if you want to access Google API on behalf of the user FROM YOUR SERVER
//hostedDomain: '' // specifies a hosted domain restriction
//forceConsentPrompt: true // [Android] if you want to show the authorization prompt at each login
//accountName: '' // [Android] specifies an account name on the device that should be used
})
.then(() => {
// you can now call currentUserAsync()
});
_signIn = async () => {
try {
await GoogleSignin.hasPlayServices(
)
const userInfo = await GoogleSignin.signIn();
console.log('User Info --> ', userInfo);
this.setState({ userInfo });
} catch (error) {
console.log('Message', error.message);
if (error.code === statusCodes.SIGN_IN_CANCELLED) {
console.log('User Cancelled the Login Flow');
} else if (error.code === statusCodes.IN_PROGRESS) {
console.log('Signing In');
} else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
console.log('Play Services Not Available or Outdated');
} else {
console.log('Some Other Error Happened');
}
}
};
The error response:
Message: A non-recoverable sign in failure occurred -catch error
I know, I am very late to answer this question. I just faced the same issue and spent almost 4-5 hours to resolve this.
The solution that I have found:
"It starts working when I have added Support Email on Firebase"
I think it's not the app or configuration issue. It may be a firebase issue that should be reported and nowhere in the doc.
Apk link https://drive.google.com/file/d/1FNFBX-M7PQC6ShCC3KSuOH2E57YGPj6H/view?usp=sharing
go to android folder ./gradlew signingReport Take the SHA1 of Task
:app:signingReport, Variant: debugAndroidTest, Config: debug Update
add fingure print sha1 in your project inside firebae.console.google.com
and download again google-service.json file in your project
[Error: A non-recoverable sign in failure occurred]
1. add support email to solve this error
2. and wait 5 minutes your google login will be working fine
Following here
cd ./android && ./gradlew signingReport
Take the SHA1 of Task :app:signingReport, Variant: debugAndroidTest, Config: debug
Update it the Firebase Console under Project Settings, Android app, add the SHA1
Download the google-services.json, put it in ./android/app
Go to Authentication, then Sign-in method, then press Google
Take the Web client ID and use that for your GoogleSignin.configure({ webClientId: ... });
This Web client ID should be the same as listed in https://console.developers.google.com/apis/credentials?project=<your_project_id> -> Credentials -> OAuth 2 Client ID -> Web Client
run gradlew signingReport in the android folder and check all the sha1 listed and if you are using firebase then make sure that all the distinct sha1 found in the list is added to the firebase project then download the google-services.json again replace it with the old one in you project and run cd android && gradlew clean and build your project again
That's due to the clientId.
In google developer console, When you configure the project for webClientID, instead of creating a new project choose an existing one, i.e create the project first and then choose it for creating credentials.
Create a new project first as of in below picture
then choose that project from the list to create credentials
It worked for me.
And coming to sign in configuration
GoogleSignin.hasPlayServices({ autoResolve: true }).then(() => {
})
.catch((err) => {
console.log("Play services error", err.code, err.message);
})
GoogleSignin.configure({
scopes: ["https://www.googleapis.com/auth/userinfo.profile"],//scopes as you need
webClientId: "***(Your clientId)",
//iosClientId: <FROM DEVELOPER CONSOLE>, // only for iOS
//offlineAccess: true, //(give it true if you need serverAuthCode i.e cross client authorisation)
//hostedDomain: ''
//forceConsentPrompt: true // [Android] if you want to show the authorization prompt at each login
//accountName: ''
})
You need to add the support email.
For that:-
Go to console.firebase.google.com
Select <YOUR_PROJECT> project.
Go to project settings
Under General tab scoll down to add support email. Add your email over there.
In my case, I've used the package name for my test app (ex. com.loginTest). After making my package name unique, I was able to solve this problem!
I searches and came across the following steps
Enable OAuth on https://console.developers.google.com
Copy and paste your SH1 while enabling
Enable Google sign in on firebase authentication
Use Oauth Client_Id instead of your WebClient ID
This fix could also help:
Go to console.developer.google.com
Select the project.
Go to Credentials.
Switch to O Auth Consent screen.
Change the app name and fill email id (optional)
Save at the bottom
Try logging in now and it should work.
Add support email in firebase and it will start working
Android
Make sure to follow these guidlines:
https://rnfirebase.io/auth/social-auth#google
https://github.com/react-native-google-signin/google-signin/blob/master/docs/android-guide.md
Dont forget to generate SHA-Keys and set them in your Firebase Console
with Simulator:
When testing on an Android Simulator, make sure GooglePlayServices are enabled.
To prove this, add a few more lines to your SignInMethod:
const signInWithGoogle = async() => {
// Wrap with try catch
try {
await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true }); // <-- Add this
const { idToken } = await GoogleSignin.signIn();
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
return auth().signInWithCredential(googleCredential);
} catch (error) {
// This will show you if GooglePlayServices is missing
console.log('With high probability, GooglePlayServices are missing on this device');
return;
}
}
The problem can reside in the app name, change it to a random (or unique) one (a name you're sure nobody else chosen), or generate a new app with a random (or unique) name.
This is because the generated React Native apps come all with the same SHA-1 fingerprint, and because Google prevents that two different Android apps registered on their cloud share the same pair of App name and SHA-1 fingerprint, you got this error (and surely you have already seen a warning on the Firebase console when creating the App!).
Source: https://support.googles.ltd/firebase/answer/6401008?hl=en&ref_topic=6399725
A complete guide to use Google signin on a React Native app: https://github.com/ubugnu/reactnative-google-signin
i don't know why but i got this error on emulator with Android 28
when i create another emulator with api 31 the error fixed!
IF YOUR APP ARE ON RELEASE:
On project, go to /android, then run ./gradlew signingReport
Copy SHA1 of release and debugTest (very important)
Go to https://console.firebase.google.com
Place all SHA1
Download Google Services JSON and put it on android/app
Build your app and run!
This worked for me.

admin.auth().currentUser; returning undefined in Cloud Function

I am trying to create a function that, when a device is registered in the app, will attach this device uid to the uid of the signed-in user who registered the device (this is in another firestore collection that is automatically created when a user registers).
Here is my code:
exports.addDeviceToUser = functions.firestore.document('device-names/{device}').onUpdate((change, context) => {
const currentUser = admin.auth().currentUser;
const deviceName = context.params.device;
var usersRef = db.collection('users');
var queryRef = usersRef.where('uid', '==', currentUser.uid);
if (authVar.exists) {
return queryRef.update({sensors: deviceName}).then((writeResult => {
return console.log('Device attached');
}));
} else {return console.log('Device attachment failed, user not signed in');}
});
I am consistently getting this error: "TypeError: Cannot read property 'uid' of undefined." Obviously I am not able to access the auth information of the current user. Why?
The Admin SDK doesn't have a sense of current user. When you say admin.auth(), you're getting back an Auth object. As you can see from the API docs, there is no currentUser property on it. Only the Firebase client SDK has a sense of current user, because you use that to get the user logged in.
If you need the client app to tell Cloud Functions code work with the user's identity, you have to send it an ID token from the client, and verify it on the server. Then the server can know who the end user is, and perform actions on their behalf. Typically you do this with an HTTP type trigger. Callable functions transmit this data automatically between the client and server, but you can do it manually yourself using code that works like this sample.
Right now, Firestore triggers don't have immediate access to the end user that made a change in the database. However, if you use the Auth UID of the user as the key of the document, and protect that document with security rules, you can at least infer the UID of the user based on the changes they make to the document by pulling it out of the id of the document that changed.
Because, by design, Cloud Functions executes on the back end and do not hold any information on which user was authenticated when adding/modifying the data in the database.
When writing the data in the 'device-names/{device}' document (from your app), you could include an extra piece of data which is the uid of the current user.

Can't destroy AWS Cognito session from within React application

I'm trying to log out of my application that's using AWS Cognito by calling their logout endpoint. I'm not using the AWS SDK because as far as I can tell, it does not yet cover oauth app integrations and sign in using external federated identity providers (please correct me if I'm wrong about that). I log in from an AWS-hosted login screen that I'm redirected to when I call their authorization endpoint. They redirect me back to my page with a "code" which I post back to them using their token endpoint to get tokens. All of this is textbook oauth 2.0 stuff.
The problem is that when I call the logout endpoint using a JavaScript browser redirect (window.location.href = ....) it doesn't clear the cookies that are set when I logged in ("XSRF-TOKEN" and "cognito") and I can't manually clear them because they were set from the AWS domain which is different from the one where my site is hosted. The cookies do get cleared when I enter the logout link in the address bar. There's clearly a difference between using window.location.href in code and dropping a link in my address bar.
To clear out the sessoin you need to use clearCachecId() and then reset the Cognito Id credentials. This is my function using the AWS SDK:
import AWS from 'aws-sdk/global';
const getCurrentUser = () => {
const userPool = newCognitoUserPool({
UserPoolId: YOUR_USER_POOL_ID,
ClientId: YOUR_APP_CLIENT_ID
});
return userPool.getCurrentUser();
}
const signOutUser = () => {
const currentUser = getCurrentUser();
if (currentUser !== null) {
curentUser.signOut();
}
if (AWS.config.credentials) {
AWS.config.credentials.clearCachedId(); // this is the clear session
AWS.config.credentials = new AWS.CognitoIdentityCredentials({}); // this is the new instance after the clear
}
}
That should take care of that.
It's a timing issue involving the use of windows.location and cookies. It seems that I was causing the same cookie, XSRF-TOKEN, to be unset and then reset so fast that it was just not happening at all. Inserting a timeout between logging out and redirecting back to the log in screen fixes the problem. There are some guys on this thread who seem to know something about it: https://bytes.com/topic/javascript/answers/90960-window-location-cookies

How to request, store, and use an access token in Meteor while using the Instagram API

How does one request, store, and use an access token from an API in the Meteor framework? I am currently trying to make requests from the (Instagram API)[https://instagram.com/developer/authentication/], but I first need to request an access token and store it for later use.
What is the general structure for doing this? I have my Client Id and Client Secret stored in the settings.json and have the services configuration package loaded. I think I need to create some sort of Method using http.get, but if someone could give a brief walkthrough that would be greatly appreciated ! Not much on this in the Meteor Docs.
You can use Bozhao Package for this.
Just install it.
meteor add bozhao:accounts-instagram
And this will work exactly like tha core accounts - facebook || google || twitter
and you can do something like this on the accountsOnCreateUser Methods
if (user.services.instagram) {
console.log("-- REGISTED USER WITH INSTAGRAM ");
instagramProfile = {
socialProfileUrl: user.services.instagram.profile_picture,
socialName: user.services.instagram.full_name,
service: "Instagram",
profileUrl: "https://instagram.com/"+ user.services.instagram.username
};
user.profile = instagramProfile;
}
Now knowing this, you can see that we have the user data inside the user.services.instagram object, there should be a accessToken and id field that you make POST / GET http request to the https://instagram.com/api/v1/.
I have never done a HTTP request to the Instagram API but it should be similar to facebook (if not sorry the below code dosnt help you to much).
Simple http call using the params.
Meteor.http.get("https://instagram.com/api/v1/", {
headers: {
"User-Agent": "Meteor/1.0"
},
params: {
access_token: user.services.accessToken
}
},function(error,result){
if(!error){
console.log(result);
}
});

Categories

Resources