#identityPool based client for guests not allowing Authenticated users

9 messages · Page 1 of 1 (latest)

vale geyser
#

I'm creating an application that has public data and admins/editors that can log in to change this public data on occasions.
My front page features a call to

const client = generateClient({ authMode: "identityPool" });
const {data, errors} = await client.models.Product.list();

The product model looks like this

Product: a
      .model({
        ...
      })
      .secondaryIndexes((index) => [
        ...
      ])
      .authorization((allow) => [
        allow.guest().to(["read"]),
        allow.authenticated("identityPool").to(["read"]),
        allow.authenticated("userPools").to(["read"]),
        allow.group("ADMINS"),
      ])

Currently Guests can view products using the list command. However as soon as I log in i get an un Unorthorized error
"If you're calling an Amplify-generated API, make sure to set the "authMode" in generateClient({ authMode: '...' }) to the backend authorization rule's auth provider ('apiKey', 'userPool', 'iam', 'oidc', 'lambda')"

The documentation recommends not using public api key and instead using guest pattern access
But I can't get the identityPool authMode to work with authenticated users. So, I might need to go back to publicApiKey access pattern for public pages.

If i try:

const client = generateClient({ authMode: "userPool" });
const {data, errors} = await client.models.Product.list();

Authenticated users can see the products but the pulic/guest users get an Unauthenticated error.

I have tried variations on:

allow.authenticated()
allow.authenticated("identityPool")
allow.authenticated("userPools")

Nothing seems to work.

tacit falcon
#

👋 for this particular use case I think api key is fine

My front page features a call to...

for IAM auth you will want authenticated and guest with identityPool. The credentials sent with the request change from guest (unauthenticated) to authenticated when you log in.

allow.authenticated("identityPool"),
allow.guest(),

and

generateClient<Schema>({ authMode: "identityPool" })
vale geyser
#

Hi @tacit falcon

I agree, i'm thinking api key is going to have to be my option.

I have tried to use your suggestion above. But Amplify keeps coming back with an Unauthenticated error when an authenticated user tries to access the data.

I'm not sure why it's not allowing an Authenticated user to read the data.
I have specified:

allow.authenticated("identityPool"),
allow.guest(),
tacit falcon
# vale geyser Hi <@143912968529117185> I agree, i'm thinking api key is going to have to be ...

hmm if you compare the auth headers that are sent with both requests are the signatures different? I'll take a further look at this, but in the mean time would you mind filing a quick bug report? https://github.com/aws-amplify/amplify-category-api/issues

GitHub

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of Graph...

vale geyser
#

@tacit falcon
I was able to find the likely cause of this. I have amplify configured with SSR as i have some API's that require SSR functions.
identityPools and Guest works when

Amplify.configure(outputs);

But fails when

Amplify.configure(outputs, { ssr: true });

So, is it the case that identityPools don't work when cognito sets auth tokens using cookies?

vale geyser
tacit falcon
summer locust
#

I have the same issue. Did you find a solution for it, @vale geyser ?

vale geyser
#

@summer locust I had to use a fairly hacky method of checking a user before creating a public client and calling for data.
It can use the existing user tokens without needing a server call. However there is a need to 1 extra server call to fetchUserGroups.
Fortunately, with a context provider this only needs to be done once when the user is authenticated.

My method was to use a flag before defining the authMode any time i needed a client.

It's a lot of extra boilerplate...

  const { isEditor } = useNavigation();

  const client = generateClient({
    authMode: isEditor ? "userPool" : "identityPool",
  });

I created a useContext component for my own purposes and wrapped the application in that.
I called NavigationProvider
As long as my provider was lower in the tree than AmplifyProvider i could make calls to amplify/auth to test the users session.

app/layout.js


import { Authenticator } from "@aws-amplify/ui-react";
import { NavigationProvider } from "@/src/lib/providers/NavigationProvider";

export default function RootLayout({ children }) {
  return(
     <html lang="en-AU">
      <body>
        <Authenticator.Provider>
          <NavigationProvider>{children}</NavigationProvider>
        </Authenticator.Provider>
      </body>
    </html>
  );
}