I am trying to use AWS Amplify's REST API with my android app. I did exactly as it was written in the docs, but I am still getting this error:
ApiException{message=AWSApiPlugin depends on AWSCognitoAuthPlugin but it is currently missing, cause=java.lang.IllegalStateException: Tried to get a plugin but that plugin was not present. Check if the plugin was added originally or perhaps was already removed., recoverySuggestion=Before configuring Amplify, be sure to add AWSCognitoAuthPlugin same as you added AWSApiPlugin.}
These are the AWS dependencies in my Gradle file:
dependencies {
// ...
implementation 'com.amplifyframework:aws-api:1.6.4'
implementation 'com.amplifyframework:core:1.6.4'
implementation 'com.amazonaws:aws-android-sdk-apigateway-core:2.3.2'
implementation 'com.amazonaws:aws-android-sdk-cognito:2.3.2'
// ...
}
This is my Application class:
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
try {
Amplify.addPlugin(AWSApiPlugin())
Amplify.configure(applicationContext)
Log.i("MyAmplifyApp", "Initialized Amplify.")
} catch (error: AmplifyException){
Log.e("MyAmplifyApp","Could not initialize Amplify.",error)
}
}
}
This error happens because you need to call Amplify.addPlugin before you make use of it.
It can also be there was an error initializing the plugin, so check the suggestion in the error when catching the exception.
So call whatever plugin you are using, preferrably in your Application class (MyApp.java) code:
public class MyAmplifyApp extends Application {
String tag = "xxx";
#Override
public void onCreate() {
super.onCreate();
//xxx
try {
Amplify.addPlugin(new AWSDataStorePlugin());
Amplify.addPlugin(new AWSCognitoAuthPlugin());
Amplify.configure(getApplicationContext());
Log.i(tag, "Initialized Amplify");
} catch (AmplifyException error) {
Log.e(tag, "Could not initialize Amplify", error);
}
}
}
How are you attempting to authenticate with your API? What is the authType listed in your app/src/main/res/raw/amplifyconfiguration.json?
If it is something involving Cognito, you need to add the Auth category. Please follow the Getting Started guide for Auth.
If you are not trying to use Cognito, update your API to use a different auth type using the CLI:
amplify update api
amplify push
For example, you might select API Key authorization, which essentially makes your API public to anyone who knows the key.
According to official Doc Add This line to my configuration function solved my problem
Amplify.addPlugin(new AWSApiPlugin());
So it become look like this
try {
Amplify.addPlugin(new AWSDataStorePlugin());
Amplify.addPlugin(new AWSApiPlugin());
Amplify.configure(getApplicationContext());
Log.i("MyAmplifyApp", "Initialized Amplify");
} catch (AmplifyException error) {
Log.e("MyAmplifyApp", "Could not initialize Amplify", error);
}
I had the same issue and the previous answers pointed me in the right direction. I was missing the line below from my initialize function, as soon as I added this in everything worked as planned.
Amplify.addPlugin(AWSCognitoAuthPlugin())
Related
I have the current workflow for my authentication
User signs in via google OAuth2
User is then given a server_auth_code which they send to my backend authentication
The auth code is validated on the back end and users is sent a JWT
I had this all working in raw Java with the Android SDK, but Flutter seemed a lot nicer. But now when using the google_sign_in plugin on android, I am unable to retrieve the serverAuthCore anymore, this plugin just wants to return null the entire time.
I Am using the client ID that's specified for Android, however, I tested the WebApplication that's auto-generated by google too but that's the same issue (Null serverAutHCode)
This is the code that I am currently using:
/// Provides the `GoogleSignIn` class
import 'package:google_sign_in/google_sign_in.dart';
class GoogleLoginPage extends StatefulWidget {
final String name = "Logging in with google.";
late GoogleSignIn _googleSignIn;
GoogleLoginPage() : super() {
_googleSignIn = GoogleSignIn(
scopes: ['https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile'],
serverClientId: "XX-XXX.apps.googleusercontent.com"
);
}
Future<void> fetchAuthToken() async {
try {
var response = await _googleSignIn.signIn();
log(response?.serverAuthCode ?? "No server auth code");
_googleSignIn.signOut();
} catch (error) {
print("ERR");
print(error);
}
}
#override
State<GoogleLoginPage> createState() => GoogleLoginState();
}
The output of this code is: [log] No server auth code
The question:
Am I doing something wrong? As mentioned this works 100% on my java project using the google play services SDK so I know it's nothing to do with my google console configurations.
Okay so I figured out the issues:
It appears that by default the google login plugin for flutter comes on an older version (If I remember correctly it was 20.0.5)
I Simply changed the version to the latest version:
'com.google.android.gms:play-services-auth:20.2.0'
You can do this by editing the project's build.gradle (In IntelliJ you open build.gradle and click "Open for editing in the android studio" in the top right, from there you need to find the gradle file for google_sign_in, and change the import there, remember to click sync in the top right of android studio before you close out of it)
And I began to receive my serverAuthCode as normal, cheers!
I have been trying to integrate AppCheck with my Android app, but I can't seem to make a valid request.
As for test purposes, I have been using the following code:
Android Code
class Application : MultiDexApplication() {
override fun onCreate() {
FirebaseApp.initializeApp(this)
val appCheck = FirebaseAppCheck.getInstance()
if (BuildConfig.DEBUG) appCheck.installAppCheckProviderFactory(DebugAppCheckProviderFactory.getInstance(), true)
else appCheck.installAppCheckProviderFactory(SafetyNetAppCheckProviderFactory.getInstance(), true)
super.onCreate()
}
}
class TestActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
val data = "This is a test!"
Firebase.functions.getHttpsCallable("test").call(data).addOnCompleteListener {
if (it.isSuccessful) {
val result = it.result.data
print(result)
}
else {
val exception = it.exception
print(exception)
}
}
}
}
Function Code
const functions = require("firebase-functions")
exports.test = functions.https.onCall((data, context) => {
if (context.app == undefined) {
functions.logger.error("Test - Failed validating device integrity!")
throw new functions.https.HttpsError("failed-precondition", "The function must be called from an App Check verified app")
}
return data
})
I have added the DebugAppCheckProviderFactory token to the Firebase console, but no matter what I do, if it is an emulator or physical device, when I call the function, the failed-precondition exception is always thrown.
Checking the function logs, I can see that the app is missing:
I have already read the documentation multiple times and I can't seem to be missing any step. Am I missing something or is there anything I can do to find the root cause for this?
Thank you for your time!
EDIT:
As for Martin suggestion, I created a new OnRequest function and added the X-Firebase-AppCheck header. I received the token correctly and was able to validate it successfully with:
firebaseAdmin.appCheck().verifyToken(appCheckToken)
So, my guess is that Android is not adding the X-Firebase-AppCheck automatically to the OnCall function like it should.
I ran the code and made some breakpoints through the code and noticed the following. The call method from Firebase is adding the Firebase-Instance-ID-Token but I can't seem to find the X-Firebase-AppCheck header anywhere. Maybe I am not supposed to see this value, or maybe I just can't find where it is being added. Or maybe it is not added at all, thus I can't validate my context.app at all.
It may be required to obtain an AppCheckToken:
FirebaseAppCheck
.getInstance()
.getAppCheckToken(false)
.addOnSuccessListener(new OnSuccessListener<AppCheckToken>() {
#Override
public void onSuccess(#NonNull AppCheckToken tokenResponse) {
String appCheckToken = tokenResponse.getToken();
...
}
});
Which has to be passed along, with the HTTP request (the example shows Retrofit, which could also be used instead of HttpsCallable:
#GET("yourExampleEndpoint")
Call<List<String>> exampleData(
#Header("X-Firebase-AppCheck") String appCheckToken,
...
);
Where FirebaseFunctions.getInstance().getHttpsCallable().call() doesn't tell how or if one has to explicitly set that X-Firebase-AppCheck header. Cloud Functions should usually receive an X-Firebase-AppCheck header - with the previously retrieved AppCheck token:
const appCheckToken = req.header('X-Firebase-AppCheck');
if (!appCheckToken) {
res.status(401);
return next('Unauthorized');
}
try {
const appCheckClaims = await firebaseAdmin.appCheck().verifyToken(appCheckToken);
// If verifyToken() succeeds, continue with the next middleware function in the stack.
return next();
} catch (err) {
res.status(401);
return next('Unauthorized');
}
One can also issue own tokens ...and checking for context-app is also valid.
Update: The Protocol specification for https.onCall reads:
Optional: X-Firebase-AppCheck: <token>
The Firebase App Check token provided by the client app making the request. The backend automatically verifies this token and decodes it, injecting the appId in the handler's context. If the token cannot be verified, the request is rejected.Available for SDK >=3.14.0
To install the minimum required NodeJS dependencies:
npm install firebase-functions#">=3.14.0"
npm install firebase-admin#">=9.8.0"
And last, but not least ...there's even a debug helper for that:
dependencies {
debugImplementation "com.google.firebase:firebase-appcheck-debug:16.0.0-beta02"
}
After testing everything with no success, in a desperate move, I tried to look to unrelated files and found the solution.
In my build.gradle I was importing all the Firebase dependencies with the bom:
implementation platform("com.google.firebase:firebase-bom:27.0.0")
implementation "com.google.firebase:firebase-crashlytics-ktx"
implementation "com.google.firebase:firebase-analytics-ktx"
implementation "com.google.firebase:firebase-firestore-ktx"
implementation "com.google.firebase:firebase-functions-ktx"
implementation "com.google.firebase:firebase-auth-ktx"
So I thought: "Can the firebase-bom be importing an outdated functions-ktx dependency?"
And guess what? As soon as I imported the dependencies without the bom, I started to see the X-Firebase-AppCheck being added and the context.app being valid.
I ended up with the following build.gralde:
implementation "com.google.firebase:firebase-crashlytics-ktx:18.2.1"
implementation "com.google.firebase:firebase-analytics-ktx:19.0.0"
implementation "com.google.firebase:firebase-firestore-ktx:23.0.3"
implementation "com.google.firebase:firebase-functions-ktx:20.0.0"
implementation "com.google.firebase:firebase-auth-ktx:21.0.1"
After a little more investigation, I found out that I was using an outdated firebase-bom version. Android Studio used to let me know if there was a new version for the dependencies, but it did not notice me for the firebase-bom. Turns out, that I just need to update my firebase-bom dependency.
TL;DR
Check your Android Firebase libraries version!
To begin with, I'm working on a Unity Game where I'm authenticating user when the game starts. My build environment is android. I'm using Firebase authentication for Google Play Games Services to authenticate user.
When the game starts in my android device or emulator, it is able to authenticate Play Games Services as well as able to connect with Firebase (I'm getting analytics data). However, when I pass the PlayGames AuthCode into Firebase.Auth Credentials, it stops executing the code (I've debug log for it). It does not throw any error in LogCat except
Firebase | server_auth_code
I tried searching web for different issues, but nothing. I checked my keys in player setting, firebase settings, OAuth 2.0 credentials on my Google API console and even check keys from my Google Play Console (which I'm not using at this stage). I have even checked my test users email addresses in Game Services and tried multiple google play games account. But issue still persist.
I'm using similar script in my other unity project where authentication works like a charm. I tried to use same script here and ended up with this issue: here. However, I solved it by removing all the packages and re-importing them into unity and changed my call functions in the script. Now, I'm stuck at this issue.
Here is cs file:
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;
using System.Threading.Tasks;
public class SetFirebase : MonoBehaviour
{
string authCode;
void Start()
{
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder().
RequestServerAuthCode(false /* Don't force refresh */).Build();
PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.Activate();
Social.localUser.Authenticate((bool success) =>
{
if (success)
{
authCode = PlayGamesPlatform.Instance.GetServerAuthCode();
Debug.Log("PlayGames successfully authenticated!");
Debug.Log("AuthCode: " + authCode);
}
else
{
Debug.Log("PlayGames SignIn Failed");
}
});
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task =>
{
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available)
{
Debug.Log("Firebase Ready!!!");
RunFirebase();
}
else
{
Debug.LogError(System.String.Format("Could not resolve all Firebase dependencies: {0}", dependencyStatus));
}
});
}
private void RunFirebase(){
Firebase.Auth.FirebaseAuth auth = Firebase.Auth.FirebaseAuth.DefaultInstance;
Debug.Log("init firebase auth ");
Firebase.Auth.Credential credential = Firebase.Auth.PlayGamesAuthProvider.GetCredential(authCode);
Debug.Log(" passed auth code ");
auth.SignInWithCredentialAsync(credential).ContinueWith(task =>
{
if (task.IsCanceled)
{
Debug.LogError("SignInOnClick was canceled.");
return;
}
if (task.IsFaulted)
{
Debug.LogError("SignInOnClick encountered an error: " + task.Exception);
return;
}
Firebase.Auth.FirebaseUser newUser = task.Result;
Debug.LogFormat("SignInOnClick: User signed in successfully: {0} ({1})", newUser.DisplayName, newUser.UserId);
});
}
}
My LogCat executes everything till "init firebase auth" but does not execute "passed auth code" so I know there is some issue in passing the credentials. It also does not run anything inside auth.SignInWithCredentialAsync(credential).
Any help or suggestion would be highly appreciated. Thank you.
There are two things I may suggest:
1) Replace ContinueWith with ContinueWithOnMainThread. This is a Firebase Extension that will guarantee that your logic runs on the main Unity thread (which tends to resolve many Unity specific issues). I go into more detail about that here.
2) Your logic may have a race condition between the Authenticate callback and the CheckAndFixDependenciesAsync continuation. These will not necessarily run in the order that you see them in your logic.
If I were building this system, I might prefer using Coroutines and a custom yield instruction:
class Authenticate : CustomYieldInstruction
{
private bool _keepWaiting = true;
public override bool keepWaiting => _keepWaiting;
public Authenticate(Social.ILocalUser user) {
user.Authenticate((bool success)=>{
/* old authentication code here */
_keepWaiting = false;
});
}
}
Then in a coroutine have something like:
private IEnumerator InitializeCoroutine() {
/* old authentication code */
// I'm ignoring error checking for now, but it shouldn't be hard to figure in.
// I'm mostly going from memory now anyway
// start both authentication processes in parallel
var authenticate = new Authenticate(Social.localUser);
var firebaseDependenciesTask = FirebaseApp.CheckAndFixDependenciesAsync();
// wait on social
yield return authenticate;
// wait on Firebase. If it finished in the meantime this should just fall through
yield return new WaitUntil(()=>firebaseDependenciesTask.IsComplete);
RunFirebase();
}
This way my logic looks roughly synchronous whilst still maintaining the asynchronosity (spell check claims that I made up that word) of the systems you're depending on and you avoid threading related issues that arise when using ContinueWith.
Let me know if that helps!
--Patrick
I am developing a shared shopping list application where an user can share his/her list with the family members. I am using Realm Object Server as a database to store all the lists and users. To grant the read permission to the other users (aka family members), I decided to use Full-Sync permissons and I found the following code snippet in appropriate Realm docs. But the problem is io.realm.PermissionManager class is not recognized in my project.
PermissionManager pm = user.getPermissionManager();
// Create request
UserCondition condition = UserCondition.username(username);
AccessLevel accessLevel = AccessLevel.WRITE;
PermissionRequest request = new PermissionRequest(condition, url, accessLevel);
pm.applyPermissions(request, new PermissionManager.ApplyPermissionsCallback() {
#Override
public void onSucesss() {
// Permissions where succesfully changed
}
#Override
public void onError(ObjectServerError error) {
// Something went wrong
}
});
To install Realm in my project I did the following step:
adding classpath "io.realm:realm-gradle-plugin:6.0.1" to project level build.gradle file
applying plugin: 'realm-android' to application level build.gradle file
Do I miss something to insert io.realm.PermissionManager to my project?
In current realm api class PermissionsManager does not exist. I checked it here:
https://realm.io/docs/java/6.0.1/api/overview-summary.html
Maybe you're using some example with old api?
More information you cand find in changelog of realm:
https://github.com/realm/realm-java/blob/master/CHANGELOG.md
In version 6.0.0 there was a breaking change with PermissionManager.
In an app we upload user activity data to Google Fit like this :
Fitness.getSessionsClient(context, GoogleSignIn.getLastSignedInAccount(context))
.insertSession(((SessionInsertRequest) object))
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
// At this point, the session has been inserted and can be read.
if (BuildConfig.DEBUG) {
Log.i(TAG, "Session insert was successful!");
}
//more success handling
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
if (BuildConfig.DEBUG) {
Log.w(TAG, "There was a problem inserting the session: " + e.toString()+ "\n"+ e.getLocalizedMessage());
}
//more error handling
}
}
});
This was working fine until approx sep 4 2019.
Then Google seemed to have changed something resulting in the following warning when creating the SessionInsertRequest
App com.foo.bar does not have access to data types in request
and in onFailureListener(...) we get the following message:
There was a problem inserting the session: com.google.android.gms.common.api.ApiException: 5002: DataType's name does not match package name.
DataTypes were not changed. They are requested when the user is asked to give permission to upload :
private FitnessOptions getFitnessSignInOptions(OAuthType type) {
switch (type) {
case Activity:
return FitnessOptions.builder()
.addDataType(DataType.TYPE_LOCATION_SAMPLE, FitnessOptions.ACCESS_WRITE)
.addDataType(DataType.TYPE_CALORIES_EXPENDED, FitnessOptions.ACCESS_WRITE)
.build();
}
}
and created in a DataSource like :
DataSource locationDataSource = new DataSource.Builder()
.setAppPackageName(packageName)
.setDataType(DataType.TYPE_LOCATION_SAMPLE)
.setName(uniqueIdentifier + "-locations")
.setType(DataSource.TYPE_RAW)
.build();
similar as the Google sample shows.
It does not matter if we omit setting the name of the dataSource or using setName(packageName). Also using setStreamName(packageName) instead does not resolve the issue.
Anybody else having this or a similar issue ?
Thank you
Robert
I wonder if the issue is related to the use of GoogleSignIn.getLastSignedInAccount. Apparently in the new version of the library this is not liked. Using GoogleSignIn.getAccountForExtension should do the trick. It worked for my issue with locations
I believe that you may have provided an invalid google-services.json file or at least one that is not compatible with the one used when you acquired permission from the user to use Google Fit.
I had the same issue: when I uploaded the new version of my app on top of the one downloaded from Google Play, it gave this error. It did not happen if instead I installed the new version of the app from scratch.
Regenerating the google-services.json file on Firebase and giving it to the new version of the app solved the issue. Now I can upload the app on top of the existing one and I do not get this error any more.
Note however that before I did not have Firebase enabled so it is possible that Google does not allow any more using google-services.json that is not generated via Firebase