Open dorontal opened 2 years ago
Hello @dorontal thanks for opening this issue.
The exception is self explanatory - There is more than one API configured for this plugin with matching endpoint type.
. This exception gets thrown when you have multiple keys under awsAPIPlugin
and using API plugin along with DataStore. DataStore requires only 1 key to be presented under awsAPIPlugin
.
Why do you need to modify the config file? I think multi-auth in Amplify library doesn't require manual modification.
Hi @HuiSF -
Why do you need to modify the config file? I think multi-auth in Amplify library doesn't require manual modification.
I need to modify the config file because - as the documentation tells us - I need to have multi-Auth for Cognito work, see: https://docs.amplify.aws/lib/restapi/authz/q/platform/flutter/#cognito-user-pool-authorization
Hi @dorontal thanks for the follow up and more details.
The document listed multi-auth modes configuration for GraphQL and REST APIs is not applicable for DataStore use case at this moment. DataStore relies on single GraphQL API to back the sync engine, and resolves valid auth method by priority as multi-auth resolution. I will do the following
@HuiSF - thanks very much for your response.
I am unable to turn off multi-auth in my app. This is a feature request to enable multi-Auth for GraphQL queries. It seems to me that this is an essential feature.
Regarding step 2 above - I'm not sure I understand - there is no need to specify which API to use for the Datastore Sync because as this link describes - multi-auth in Amplify library - Datastore's library does this selection (of authorization type) automatically -- see table after following the link to the documentation -- so the library already probably has code for that automatic selection of the proper API configuration to use (Datastore derives which auth to use, from the schema, as the doc points out) which would imply that this feature is almost fully implemented already.
Hey @dorontal sorry for the confusion. those two steps are meant for me to take actions :D
For point 2, taking your configuration, we should be able to do
final datastore = AmplifyDataStore(
modelProvider: ModelProvider.instance,
apiName: 'tracktunesCognito',
);
So when you have multiple GraphQL endpoints listed in the configuration, DataStore can still work.
@HuiSF
BTW, there is another named parameter (mentioned in the documentation) that must be added for using multiAuth
and that is authModeStrategy
, e.g:
AmplifyDataStore(
modelProvider: ModelProvider.instance,
authModeStrategy: AuthModeStrategy.multiAuth,
),
it was my understanding that the Datastore would try to automatically deduce which auth to use from the schema, when this flag authModeStrategy
is set to AuthModeStrategy.multiAuth
.
Not sure why you want to add the apiName
or how it would help as the DataStore will need both apiNames not just one of them - one for IAM, one for Cognito.
authModeStrategy: AuthModeStrategy.multiAuth
this parameter doesn't resolve valid auth between GraphQL API configurations. It still requires 1 GraphQL endpoint to be listed in the configuration file, (so it won't fix the exception you encountered).
apiName: 'tracktunesCognito'
will be an upcoming improvement (I renamed your issue and marked it as a feature request), please stay tuned.
@HuiSF
The statement authmodeStragegy: AuthModeStrategy.multiAuth
"doesn't resolve valid auth between GraphQL API" - does not make sense to me - I thought that DataStore does resolve the valid auth, automatically, as the documentation says, when it sees that flag.
Thinking about the apiName
feature request a bit more, it makes less sense now, because an addition of apiName
to AmplifyDataStore()
would let you use GraphQL with only one Auth, not multiple Auths.
In the case of the apiName
flag to AmplifyDataStore()
the API name would be specified at the configuration level - at the call to Amplify.addPlugins()
- which means it would be set in stone once your app starts, which means multi-Auth will not be possible for GraphQL APIs with that flag.
[ I know Amplify Datastore it's still early code - so very grateful for this library overall, the benefits are immense! Thanks so much! ]
I think there is misunderstanding here...
The multi-auth modes for GraphQL and REST using Amplify API plugins is conceptually different from multi-auth in DataStore.
The former - configure multiple APIs, each API is with a different auth mode, you choose which API to use in order to choose a specific auth mode.
The latter - DataStore relies on a single GraphQL API, it resolve a usable auth method (providing valid token for this GraphQL PI) from an array of choosable auth methods (listed by @auth
directive in model schema).
Configuring multi-auth modes in API doesn't do anything for DataStore multi-auth. Hope that makes sense.
We need to introduce apiName
for DataStore in order to support this particular configuration of yours, which has multiple GraphQL endpoints listed.
But if you don't need multiple GraphQL API endpoints (the configuration file has only 1 GraphQL endpoint), DataStore multi-auth is already supported.
Hi @HuiSF, the issue is that when you configure the same GraphQL API endpoint with a Cognito user pool authorization type by adding a block in the amlifyconfiguration.dart
- for some reason this causes the exception to be thrown by DataStore
init. DataStore cannot handle the fact that the amplifyconfiguration.dart
has changed in that way at the API section - but that change was the one that's documented by Amplify for us to do in order to get the app to use Cognito authorization with the GraphQL API. That part works in my app with the API but not with DataStore: as soon as I introduced it - it caused the DataStore
to throw the exception and fail.
Moreover, when I remove the Cognito Authorization section from the amplifyconfiguration.dart
then DataStore
no longer throws that exception.
That is what I call a bug, not a feature request.
I do not see how adding apiName
to DataStore
initialization at the call to Amplify.addPlugins(..., AmplifyDatastore(..., apiName: ....
would help. The DataStore
cannot be tied to a single API at that level - it needs to handle more than one API but apiName
ties it to just one API which is exactly what you are trying to avoid.
The only options I have right now are:
1) Do not use DataStore
until it can handle the two authorizationType
blocks in the GraphQL API section of amplifyconfiguration.dart
- i.e until it no longer throws an exception
2) Stop using GraphQL with multi-Auth, only use it with single Auth (I cannot afford to do that in my app, it needs multi-Auth)
Why is this not a bug? DataStore
is throwing an exception with valid code.
As this DataStore
Amplify documentation mentions, when a GraphQL model has multiple @auth
rules,
the rules will be ranked by priority (see below), and DataStore will attempt the synchronization with each authorization type until one succeeds (or they all fail).
This implies that
1) DataStore
uses GraphQL API
2) when there is a GraphQL API with one endpoint but two authorizations (one being IAM, the other being Cognito, as in my setup above) then DataStore
, when it tries to sync with the public @auth
rules it will need to use the GraphQL API that was configured for IAM and when DataStore
tries to sync with private
or allow: owner
@auth
rules it will need to use the GraphQL API that was configured for Cognito. It is my understanding that DataStore
is supposed to figure out automatically not only which @auth
rule to use but also which API configuration in amplifyconfiguration.dart
goes with which @auth
rule that it is trying to sync with - as it mentions, it will try to sync with all the @auth
rules in your schema until one succeeds or all fail. This implies that DataStore
must consult both the Cognito API section and the IAM API section, depending on which @auth
rule it is currently trying. This is why adding an apiName
does not seem to help - DataStore
will need to try all configured GraphQL APIs that have the same endpoint in the amplifyconfiguration.dart
in order to go through all the @auth
rules - it cannot just rely on one of the APIs - that is not enough for it to go through all the Auth rules.
I do not understand how adding apiName
to the DataStore
at configuration can help or what it can help with, with respect to this bug.
Here's a summary of my findings:
api
key in configuration file. (configuration files looks like the one pasted in this issue)auth
keyapi
key in the configuration file.Hi @dorontal for the original issue you posted, it was due to point 4.
Do you want to use multi-auth with API plugin, and also need DataStore in the same App? If so, unfortunately it's not working due to the reason explained above, we would need to provide the feature from DataStore allowing specifying which GraphQL endpoints to let DataStore use.
Or do you want to use multi-auth for only DataStore? If so, please follow the Amplify CLI multi-auth configuration mentioned in point 3, and specify authModeStrategy: AuthModeStrategy.multiAuth
when initiate DataStore.
Hi @HuiSF - and thank you for your response and for the informative explanation. Nothing in this explanation is new to me, however, and this explanation is exactly my reason for opening this issue, specifically, your step 4 is this issue.
Not using multi-auth in API is not an option for us. App is already using multi-auth with API plugin. It has to use multi-Auth, because it provides a services to people who don't even have an account and have never logged in (guests) like the ability to see a limited view of any user's profile or the ability to view publicly posted documents. But the GraphQL API also needs to provide many services to signed-in users, such as seeing private documents. So both API configurations are set up - one to use IAM and the other to use Cognito, as prescribed by the documentation and as you can see in amplifyconfiguration.dart
and it works just fine.
One minor clarification of point #4 above: it's not that GraphQL uses multiple endpoints - there is always only one endpoint for GraphQL: if you look in my amplifyconfiguration.dart
above, for example, you'll see that the URL for both tracktunes
and tracktunesCognito
is exactly the same endpoint. I believe you meant "DataStore currently doesn't support multiple GraphQL configuurations or "API configurations" but it's not an endpoint, which is a URL, which is the same for both. One of the main features of GraphQL is that it always uses only one endpoint. I think it may be clearer to use "configuration" instead of endpoint.
So yes, the conclusion remains the same: that DataStore is not yet usable when the GraphQL API is configured with more than one authorization type. I cannot use it.
What's interesting is that the DataStore documentation on multi Auth seems to suggest that DataStore is supposed to work out of the box in this case when the GraphQL API is configured with more than one authorization type. The documentation even goes as far as to say that DataStore can pick the proper @auth
rule automatically - and this means it knows how to pick either the IAM version or the Cognito version of the GraphQL API automatically. That's what the documentation claims. But when I run it, it throws an exception that contradicts the documentation - I think that exception should not be thrown and instead it would be nice to see DataStore automatically pick the right GraphQL API auth configuration, as the documentation claims it can.
it's not that GraphQL uses multiple endpoints - there is always only one endpoint for GraphQL
I was thinking GraphQL + different Auth = different endpoints as they are requiring different tokens.
What's interesting is that the DataStore documentation on multi Auth seems to suggest that DataStore is supposed to work out of the box
This is based on the assumption configuring DataStore multi-auth using Amplify CLI. and -
DataStore can pick the proper @auth rule automatically
DataStore picks up the auth info from the information under the auth
key, not from the api
key.
The documentation is confusing, the API multi-auth is not related to DataStore multi-auth at all. :/ Will fix this. All this is due to a lack of support to use API plugin and DataStore plugin in the same App. The improvements are on their way.
FYI, just noticed that there is another similar issue to this one - #1651
Does anybody have any idea when this issue will be fixed?
Hi @dorontal amplify-flutter DataStore supports multi-auth.
This issue is that the multi-auth for API plugin and multi-auth for DataStore are not compatible with each other as I explained in previous discussion.
We've updated the documentation of multi-auth in API plugin to state this issue. This issue is also recorded in https://github.com/aws-amplify/amplify-flutter/issues/1945 (point 5) to track the solution of this issue that is currently being investigated, thank you for your patience.
Hi @HuiSF - thank you for the clarification that this is being dealt with, also for the clarification of the incompatibility issue, which I think I understand better now. Definitely will wait patiently but it's good to know that we are being listened to, thanks so much!
Hey @dorontal sorry for the confusion. those two steps are meant for me to take actions :D
For point 2, taking your configuration, we should be able to do
final datastore = AmplifyDataStore( modelProvider: ModelProvider.instance, apiName: 'tracktunesCognito', );
So when you have multiple GraphQL endpoints listed in the configuration, DataStore can still work.
Has this part been addressed? We have multiple GraphQL endpoints and need a way to specify for DataStore.
Hi @HuiSF - what is your current ETA for resolving this issue? It has been around for almost six months - still unable to use DataStore because of it. Thanks.
Hi @dorontal sorry for the delayed response and thanks for your patience, we are communicating with amplify-swift and amplify-android maintainers as well as relevant internal teams regarding this issue to determine a suitable long term solution. I'll update the progress.
@HuiSF -- In case you were wondering why I believe multi-mode authorization is common / needed, here's our use case that demands it and which I believe is shared by many apps:
I'm putting this use-case here also because maybe somebody can suggest a way to implement this use-case without using multi-auth, which would also allow us to move forward.
Our use-case that needs multi-auth is this;
1) DynamoDB saves a user-profile model for each user of our app, accessed via GraphQL 2) Some fields in the user model (e.g. how much money they've made) are private and can only be seen by the owner user 3) We still want to be able to show the non-private fields of any user's profile to anyone -- even people without an account at all, or users who are not signed in, should be able to see limited user profile information about other users (e.g, if you go to your Github home page while signed out, you still can see some stats about your username there)
If we only needed parts 1 and 2 above, we'd be able to get by with Cognito authorization alone, no multi-auth needed.
But if we want to share info about users with anybody, as in part 3, we must use IAM for that, hence we must use multi-auth in such an app.
This use case is why I think this issue is very important not just to me, but to many others. It seems to me like it would be a common use case.
BTW, for those of you who need a workaround, I am using this workaround: created a lambda function that performs the needed DB operation (just a GET, in my case); the lambda function is accessed by guest users via IAM and a REST API.
Description
When you have more than one Auth configured in
amplifyconfiguration.dart
- the functionAmplify.DataStore.observeQuery()
throws an exception. You can see in the console errors that are provided from the Android emulator that the failure is due to the fact that Amplify Flutter cannot yet handle multiple Auth in the same configuration file. But the Amplify Flutter documentation explains in detail that this should be available, (see https://docs.amplify.aws/lib/datastore/setup-auth-rules/q/platform/flutter/#configure-multiple-authorization-types).Here are the log lines from the VSCode console - those come from the Amplify libraries and/or Android libraries running on Android emulated OS:
Categories
Steps to Reproduce
amplifyconfiguration.dart
so that under API you have one GraphQL API configuration block for withauthorizationType: AMAZON_COGNITO_USER_POOLS
and in a second block under the sameapi
section add a seond GraphQL API configuration block withauthorizationType: AWS_IAM
(see how it's done in thetracktunes
andtracktunesCognito
sections inamplifyconfiguration.dart
below).Amplify.Datastore.observeQuery(<YOUR MODEL>)
at the start of your program and you'll see it crashing (check log lines in VSCode of the Android emulator, giving out the Android/Java-level exception details)Screenshots
No response
Platforms
Android Device/Emulator API Level
API 29
Environment
Dependencies
Device
Samsung Galaxy S7 -- emulated
OS
Android 8
CLI Version
9.1.0
Additional Context
Here's the
amplifyconfiguration.dart
file: