Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best practice for public and private access to Amplify resources #4178

Closed
blairtaylor opened this issue Oct 13, 2019 · 13 comments
Closed

Best practice for public and private access to Amplify resources #4178

blairtaylor opened this issue Oct 13, 2019 · 13 comments
Assignees
Labels
AppSync Related to AppSync issues question General question SSR Issues related to Server Side Rendering

Comments

@blairtaylor
Copy link

Our project will require a user to initially have public access to some of our schema types and once they have chosen the products they would like to purchase, they will be required to authenticate and pay/purchase the items. We have most of the authenticated site built (and working) and are now looking at the design for the public site. We are using Cognito user pools.

One additional requirement is the public site will need to use SSR (Next.js) to support SEO.
In future we will also be adding React Native apps.

We are currently thinking of setting up a separate publicly accessible site in addition to our current "private" site and using manual config in the aws-exports.js file to point to the existing AppSync endpoint. For the tables requiring public access, we would set the @auth(rules: [{allow: public}]) annotation. We'd also use next.js on the new public site (but not the private site since it would not require SSR/SEO). Having separate sites seems to simplify the SSR issues.

The other option is to use AWS AppSync Multi-Auth and have the public site use API_KEY as the auth type. It seems that the @auth(rules: [{allow: public}]) annotation is essentially doing this for us. This seems to be an all or nothing approach. In our case it is only a small subset of the tables for which we would grant public access.

We're concerned about security and would like to take the path which provides public access only to those schema types which contain publicly accessible information.

We'd appreciate input on the best way to implement the public portion of our Amplify solution.

@elorzafe elorzafe added AppSync Related to AppSync issues question General question SSR Issues related to Server Side Rendering pending-close-response-required labels Oct 15, 2019
@elorzafe
Copy link
Contributor

@blairtaylor any reason you need to use SSR?

@blairtaylor
Copy link
Author

The consultant handling our SEO has indicated that we need SSR so that the web crawlers can properly index our site. He has told us that client rendered React sites will not work well with SEO.

@jkeys-ecg-nmsu
Copy link

@blairtaylor if that's the only reason for SSR you might be able to get away with a solution like prerender.io.

@blairtaylor
Copy link
Author

Thanks. We'll investigate prerender.io.

Still would appreciate opinions on the best way to offer a public flow for our site which involves around 20% of the site and the two options I outlined to access the DynamoDB types. To clarify, we have an order flow which will behave differently between authenticated and non-authenticated users.

@jkeys-ecg-nmsu
Copy link

I think the Amplify team has added field-level @auth directives. Check the GraphQL Transformer docs for this use case.

If that doesn't work, you could create another schema and AppSync API that mirrors your private schema and that uses the same data sources but only exposes the public models/fields. (Not sure if this is possible with the current CLI.)

Note: before deploying a solution like that please test it b/c IDK if the generated resolvers will reject requests to a public API (API key) that request data that's not specified in the schema itself. If they don't prevent that you would be exposing your private fields.

@jkeys-ecg-nmsu
Copy link

@blairtaylor does field-level authorization meet your needs?

@blairtaylor
Copy link
Author

blairtaylor commented Oct 24, 2019

I believe so @jkeys-ecg-nmsu . We'll need to test it out.

With @auth rules, can you apply a higher level of security for the overall type and looser security for non-sensitive fields?

Ex.

type User @model @auth(rules: [{allow: groups, groups: ["Admin"]}])
{
id: ID!
username: String
ssn: String
name: String @auth(rules: [{allow: public}])
bio: String @auth(rules: [{allow: public}])
}

So a non-authenticated user could query the User type but only retrieve name and bio?

Thanks.

@anarerdene
Copy link

Hi @blairtaylor , Im using nextJS and AppsyncSDK and main auth is Cognito. I have same problem with you. In my case 70% cognito query 30% public query.

So i created multiple Apollo client like this.

function createApolloClient(initialState) {
  const client = new AWSAppSyncClient(
    {
      url: config.aws_appsync_graphqlEndpoint,
      region: config.aws_appsync_region,
      auth: {
        type: config.aws_appsync_authenticationType,
        jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken()
      },
      disableOffline: true
    },
    {
      cache: new InMemoryCache().restore(initialState || {}),
      ssrMode: true,
      connectToDevTools: true
    }
  );

  const clientPublic = new AWSAppSyncClient(
    {
      url: config.aws_appsync_graphqlEndpoint,
      region: config.aws_appsync_region,
      auth: {type: AUTH_TYPE.API_KEY, apiKey: config.aws_appsync_apiKey},
      disableOffline: true
    },
    {
      cache: new InMemoryCache().restore(initialState || {}),
      ssrMode: true,
      connectToDevTools: true
    }
  );

  if (userCheck() === true) {
    return client;
  }

  return clientPublic;
}

Because

 @auth(rules: [{allow: public, provider: apiKey, operations: [read]}])

not working on single apollo client. I don't know why ?

@iamgerardm
Copy link

How can we rely on API key when it changes every 7 days?

@ericclemmons ericclemmons added this to the Support SSR milestone Mar 17, 2020
@mauerbac
Copy link
Member

Hi @iamgerardm - this constraint is mainly suggested for development and can be changed here

AWS AppSync API keys expire seven days after creation, and using API KEY authentication is only suggested for development. To change the AWS AppSync authorization type after the initial configuration, use the $ amplify update api command and select GraphQL.

@stale
Copy link

stale bot commented Apr 23, 2020

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

@stale stale bot closed this as completed Apr 23, 2020
@ericclemmons ericclemmons self-assigned this Apr 24, 2020
@dtelaroli
Copy link

Hi @blairtaylor , Im using nextJS and AppsyncSDK and main auth is Cognito. I have same problem with you. In my case 70% cognito query 30% public query.

So i created multiple Apollo client like this.

function createApolloClient(initialState) {
  const client = new AWSAppSyncClient(
    {
      url: config.aws_appsync_graphqlEndpoint,
      region: config.aws_appsync_region,
      auth: {
        type: config.aws_appsync_authenticationType,
        jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken()
      },
      disableOffline: true
    },
    {
      cache: new InMemoryCache().restore(initialState || {}),
      ssrMode: true,
      connectToDevTools: true
    }
  );

  const clientPublic = new AWSAppSyncClient(
    {
      url: config.aws_appsync_graphqlEndpoint,
      region: config.aws_appsync_region,
      auth: {type: AUTH_TYPE.API_KEY, apiKey: config.aws_appsync_apiKey},
      disableOffline: true
    },
    {
      cache: new InMemoryCache().restore(initialState || {}),
      ssrMode: true,
      connectToDevTools: true
    }
  );

  if (userCheck() === true) {
    return client;
  }

  return clientPublic;
}

Because

 @auth(rules: [{allow: public, provider: apiKey, operations: [read]}])

not working on single apollo client. I don't know why ?

AppSync uses multiple auth type with different header.
I was trying use like this:

const authLink = setContext(async (_, { headers }) => {
  // get the authentication token from local storage if it exists
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      'Authorization': (await Auth.currentSession()).getIdToken().getJwtToken(),
      'X-Api-Key': aws_exports.aws_appsync_apiKey,
    }
  }
});

The cognito auth does not work if I send the X-Api-Key.
It's hard to configure multiples Apollo Client and I will use group auth to authorise the public data after login.
AppSync it's very discouraging sometimes.

@github-actions
Copy link

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 29, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
AppSync Related to AppSync issues question General question SSR Issues related to Server Side Rendering
Projects
None yet
Development

No branches or pull requests

8 participants