Is there a way to use @auth(rules: [{ allow: owner }]) transform if the GraphQL authentication type is set to IAM? Looks like the @auth transform only works when the GraphQL authentication type is set to cognito user pool.
I'd like to use the @auth feature, but my application requires backend mutations via lambda. From what I read, I don't think I can use GraphQL api from lambda unless I set my authentication to IAM.
What's the best practice when you want to use @auth transform, also want to make updates to your GraphQL backend via lambda?
At this point @auth is only valid for Cognito User Pools but we're looking at IAM in the future. I've tagged this as a feature request.
I am also using IAM. One benefit of using it is that you can have auth and unauth users, as described here.
When you implement @auth for IAM, it would then be great if you can also automate migration of user data from the unauth state to the auth state.
Thanks a lot !
I might be misunderstanding this issue, but is the following possible with the current Amplify package?
@undefobj Is it possible to use Cognito Pools and the @auth directive, but also to update data in the backend via lambda? Is it possible to update the backend by accessing the GraphQL endpoint directly? Is it possible to update the backend by updating the DynamoDB items directly?
For instance:
Let a BookReviewPost model be defined as such:
type BookReviewPost @model
@auth(rules: [
{ allow: owner, mutations: [create], queries: [get, list] },
# Admin users can access any operation.
{ allow: groups, groups: ["Admin"] }
])
{
id: ID!
status: String!
review: String!
}
John the User makes a BookReviewPost using amplify API (type: graphql) and there is a backend approval process for all Book Reviews. Thus, the initial BookReviewPost object has status = "PENDING_APPROVAL" (let's pretend that the graphql transform hardcodes status to PENDING_APPROVAL in the backend so that John the User can't get sneaky )
Then, Jill the Reviewer (who is in the Admin cognito group) can review the BookReviewPost in her Web Admin Dashboard by querying the data. If she approves the post, she can update the status field to APPROVED using the Amplify.API package.
I believe that all of the above is completely possible and is how the system is designed.
Now, Jill the Reviewer is actually an asynchronous lambda function who is checking for certain keywords or sentiment or something:
From a lambda, if you use the aws-amplify package and use Auth.login() with valid credentials (i.e a service account that you create), you can call the graphql endpoint, with the cognito pool setup.
By-passing the graphQL endpoint is bad in most cases because you loose validations and subscriptions.
I think the issue here is that with the AWS_IAM setup in AppSync, the @model directive doesn't generate resolvers that are valid (because the $context.identity is different with AWS_IAM)
Ah, okay that makes sense. I linked this issue in the auth directive RFC, could amplify create an IAM role and generate the resolvers such that $context.identity is overriden if the correct IAM role is calling the resolver?
@rohitspujari Had you considered the approach that @vparpoil suggests? Creating a service account that your lambda function logs into?
@ajhool @vparpoil Re: creating a Service Account for the lambda to log into and invoke AppSync queries and mutations, are there any best practices or recommendations around doing so? More importantly, any no-no's in order to avoid security issues?
@kwhitejr
The usual security issues... create least-privileged users who only have privileges to do what they need to do. I just use a user in an "Admin" cognito group, but I might create more fine-grained service groups with more constrained access.
Here's how I store/retrieve passwords for login.
import { SecretsManager } from 'aws-sdk';
interface IServiceCreds {
username: string;
pass: string;
}
/**
* TODO: Inject ssm param names so we can use different ones for dev/test/prod, etc
*/
export const getServiceCreds = async (): Promise<IServiceCreds> => {
const secretsManager = new SecretsManager({region: 'us-east-1'});
const user = await secretsManager.getSecretValue({ SecretId: 'nds-service-user-dev' }).promise();
if (!user || !user.SecretString) {
throw new Error('Secret not found')
}
return JSON.parse(user.SecretString!);
}
...
// WARNING: NEVER LOG
const creds = await getServiceCreds();
// WARNING: NEVER LOG
await Auth.signIn(creds.username, creds.pass);
// WARNING: NEVER LOG
We launched multi-auth support for AppSync API (which included public APIs - with API Keys + IAM) as a part of our CLI version 3.8+.
Please take a look at our documentation around it out here for more info - https://aws-amplify.github.io/docs/cli-toolchain/graphql#public-authorization
Most helpful comment
From a lambda, if you use the aws-amplify package and use Auth.login() with valid credentials (i.e a service account that you create), you can call the graphql endpoint, with the cognito pool setup.
By-passing the graphQL endpoint is bad in most cases because you loose validations and subscriptions.
I think the issue here is that with the AWS_IAM setup in AppSync, the @model directive doesn't generate resolvers that are valid (because the
$context.identityis different with AWS_IAM)