Coder Social home page Coder Social logo

Comments (4)

chrisbonifacio avatar chrisbonifacio commented on June 12, 2024

Hi @gpavlov2016 👋 it seems that this may be intended behavior. When I try to deploy the same schema, I get this error:

InvalidDirectiveError: 'listen' operations are specified in addition to 'read'. Either remove 'read' to limit access only to 'listen' or only keep 'read' to grant all get,list,search,listen,sync access.

read encompasses listen/subscribe permissions. Can you let us know what your use case is?
For example, do you want the user to be able to subscribe without being able to perform list queries?

from amplify-js.

gpavlov2016 avatar gpavlov2016 commented on June 12, 2024

Thanks for looking into this @chrisbonifacio. My scenario is:

  • React client that uses Cognito authentication with owner authorization to allow all operations on users' own data
  • Android client with API Key auth with read access only to all data (from all users). Read access includes queries and subscriptions.

When I try with read access only for public auth, the queries on Android work but the subscriptions fail.
I did some digging into the Android amplify library and it seems like it is related to this comment

from amplify-js.

renebrandel avatar renebrandel commented on June 12, 2024

hi @gpavlov2016 the read operation includes listen access. So the listen operation in the list here is a no-op. So this might be a red herring.

Another common reason we see why subscription "come across as failing" is because the GraphQL selection set of the mutation must include all the fields that the subscriber is looking for. Can you share the code where you trigger the mutation and the Android code where you listen to the subscription?

from amplify-js.

gpavlov2016 avatar gpavlov2016 commented on June 12, 2024

The subscription fails at the authentication stage before I even try to do any mutation, and based on the logs it's trying to use Cognito for authentication. Query operation with the same code succeeds.
Here is how the model is defined in the React client:

const schema = a.schema({
  Video: a
    .model({
      title: a.string(),
      timeOfDayStart: a.time(),
      timeOfDayEnd: a.time(),
      dateStart: a.date(),
      dateEnd: a.date(),
      impressionsTarget: a.integer(),
      zipCode: a.string(),
      s3Key: a.string(),
      thumbnail: a.string(),
      isRunning: a.boolean(),
    })
    .authorization([
      a.allow.public().to(['read']),
      a.allow.owner().to(['create', 'read', 'update', 'delete']),
    ]),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: 'userPool',
    apiKeyAuthorizationMode: {}
  },
});

And here is how the model is defined in the Android client (autogenerated from using amplify config file).

@ModelConfig(pluralName = "Videos", type = Model.Type.USER, version = 1, authRules = {
  @AuthRule(allow = AuthStrategy.PUBLIC, operations = { ModelOperation.READ }),
  @AuthRule(allow = AuthStrategy.OWNER, ownerField = "owner", identityClaim = "cognito:username", provider = "userPools", operations = { ModelOperation.CREATE, ModelOperation.READ, ModelOperation.UPDATE, ModelOperation.DELETE })
}, hasLazySupport = true)
public final class Video implements Model {
...
}

And this is the code that calls the subscribe method:

val onCreateSubscription = Amplify.API.subscribe(
            ModelSubscription.onCreate(Video::class.java),
            { Log.i("ApiQuickStart", "Subscription established - onCreate") },
            {
                Log.i("ApiQuickStart", "Video create subscription received: ${(it.data as Video).title}")
                addVideoToPlaylist(it.data)
            },
            { Log.e("ApiQuickStart", "Subscription failed - onCreate", it) },
            { Log.i("ApiQuickStart", "Subscription completed - onCreate") }
        )

For reference, this is the query call that works with the same settings:

Amplify.API.query(
            ModelQuery.list(Video::class.java, Video.IS_RUNNING.eq(true)),
            { response ->
                val page = response.data
                initVideoUris(page.items.toList())
                Log.d("refreshItems", page.toString())
                Log.i("MyAmplifyApp", "Queried items: $page")
            },
            { Log.e("MyAmplifyApp", "Query failure", it) }
        )

Error message from logcat:

Subscription failed - onCreate
ApiAuthException{message=Token is null, cause=null, recoverySuggestion=Sorry, we don't have a suggested fix for this error yet.}
at com.amplifyframework.api.aws.sigv4.DefaultCognitoUserPoolsAuthProvider.fetchToken(DefaultCognitoUserPoolsAuthProvider.java:81)
at com.amplifyframework.api.aws.sigv4.DefaultCognitoUserPoolsAuthProvider.getLatestAuthToken(DefaultCognitoUserPoolsAuthProvider.java:87)
at com.amplifyframework.api.aws.auth.AuthRuleRequestDecorator.getAuthToken(AuthRuleRequestDecorator.java:226)
at com.amplifyframework.api.aws.auth.AuthRuleRequestDecorator.getIdentityValue(AuthRuleRequestDecorator.java:152)
at com.amplifyframework.api.aws.auth.AuthRuleRequestDecorator.decorate(AuthRuleRequestDecorator.java:121)
at com.amplifyframework.api.aws.AWSApiPlugin.buildSubscriptionOperation(AWSApiPlugin.java:636)
at com.amplifyframework.api.aws.AWSApiPlugin.subscribe(AWSApiPlugin.java:315)
at com.amplifyframework.api.aws.AWSApiPlugin.subscribe(AWSApiPlugin.java:295)
at com.amplifyframework.api.ApiCategory.subscribe(ApiCategory.java:91)
at com.example.androidamplifygen2.MainActivity.subscribe(MainActivity.kt:208)
at com.example.androidamplifygen2.MainActivity.onCreate(MainActivity.kt:106)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
2024-04-08 18:24:07.756 6648-6700 MyAmplifyApp com.example.androidamplifygen2 E Query failure
ApiException{message=OkHttp client failed to make a successful request., cause=ApiAuthException{message=Failed to retrieve auth token from Cognito provider., cause=ApiAuthException{message=Token is null, cause=null, recoverySuggestion=Sorry, we don't have a suggested fix for this error yet.}, recoverySuggestion=Check the application logs for details.}, recoverySuggestion=Sorry, we don't have a suggested fix for this error yet.}
at com.amplifyframework.api.aws.AppSyncGraphQLOperation.dispatchRequest(AppSyncGraphQLOperation.java:109)
at com.amplifyframework.api.aws.AppSyncGraphQLOperation.$r8$lambda$s0tPt9Vu7puSi2-I-7S0nxLOkUY(Unknown Source:0)
at com.amplifyframework.api.aws.AppSyncGraphQLOperation$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: ApiAuthException{message=Failed to retrieve auth token from Cognito provider., cause=ApiAuthException{message=Token is null, cause=null, recoverySuggestion=Sorry, we don't have a suggested fix for this error yet.}, recoverySuggestion=Check the application logs for details.}
at com.amplifyframework.api.aws.auth.ApiRequestDecoratorFactory.forAuthType(ApiRequestDecoratorFactory.java:127)
at com.amplifyframework.api.aws.auth.ApiRequestDecoratorFactory.fromGraphQLRequest(ApiRequestDecoratorFactory.java:100)
at com.amplifyframework.api.aws.AppSyncGraphQLOperation.dispatchRequest(AppSyncGraphQLOperation.java:93)
at com.amplifyframework.api.aws.AppSyncGraphQLOperation.$r8$lambda$s0tPt9Vu7puSi2-I-7S0nxLOkUY(Unknown Source:0) 
at com.amplifyframework.api.aws.AppSyncGraphQLOperation$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0) 
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) 
at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:923) 
Caused by: ApiAuthException{message=Token is null, cause=null, recoverySuggestion=Sorry, we don't have a suggested fix for this error yet.}
at com.amplifyframework.api.aws.sigv4.DefaultCognitoUserPoolsAuthProvider.fetchToken(DefaultCognitoUserPoolsAuthProvider.java:81)
at com.amplifyframework.api.aws.sigv4.DefaultCognitoUserPoolsAuthProvider.getLatestAuthToken(DefaultCognitoUserPoolsAuthProvider.java:87)
at com.amplifyframework.api.aws.auth.ApiRequestDecoratorFactory.forAuthType(ApiRequestDecoratorFactory.java:125)
at com.amplifyframework.api.aws.auth.ApiRequestDecoratorFactory.fromGraphQLRequest(ApiRequestDecoratorFactory.java:100) 
at com.amplifyframework.api.aws.AppSyncGraphQLOperation.dispatchRequest(AppSyncGraphQLOperation.java:93) 
at com.amplifyframework.api.aws.AppSyncGraphQLOperation.$r8$lambda$s0tPt9Vu7puSi2-I-7S0nxLOkUY(Unknown Source:0) 
at com.amplifyframework.api.aws.AppSyncGraphQLOperation$$ExternalSyntheticLambda0.run(D8$$SyntheticClass:0) 
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:462) 
at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
at java.lang.Thread.run(Thread.java:923) 

from amplify-js.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.