aws-amplify / aws-amplify/amplify-data

Dynamic Group Authentication Support for Custom Queries

Open
#438 0 comments 0 reactions 0 assignees View on GitHub
data-schema feature-request Gen 2
Dominant language
TypeScript
Stars
18
Forks
23
Avg merge
26m
Merged PRs (30d)
1

Description

### Describe the feature you'd like to request

I'm building a multi-tenant application with Gen2. Each of my models has a `tenantId` attribute on it, and each user belongs to a Group in Cognito with that tenantId name. (I'm using Postgres for my database).

```
models.User.authorization((allow) => [
allow.groupDefinedIn('tenantId'),
]),
```

This works great and ensures that the tenancy is enforced without any work on the client side and allows me to easily ensure my queries don't leak data from other tenants.

Now I need to add some custom queries. I wrote a stored procedure in postgres to let me do a fuzzy search for users by multiple attributes, so I want to run the following:

```
searchUsers: a.query()
.arguments({
lookup: a.string().required()
})
.returns(a.ref("user").array())
.handler(a.handler.inlineSql(
`SELECT * FROM public.search_user(:lookup);`
)).authorization(allow => allow.authenticated()),
```

But here, the `groupDefinedIn` method is not supported, so the best I can do is `authenticated()`. This means that my tenancy is not enforced without passing in the `tenantId` from the client which can be easily modified (not secure).

Amplify doesn't pass the Cognito auth context to the database either, so I can't modify my stored procedure to use something like `WHERE tenant_id = current_setting['appsync.identity_claims_custom_tenantId']`.

The workaround for now is to move all of this to a custom Lambda function and manage it all manually, but that means losing out on the super simple way of handling custom queries in Gen 2.

### Describe the solution you'd like

There are two possible solutions here:

1) the preferred approach would be to allow custom queries to support the `groupDefinedIn()` method. This would let me treat my custom queries the same way I handle the rest of my models and their associated queries.

2) alternatively, if the auth context were to be passed to the database, then I could write my own enforcement logic into the database itself using row level security or WHERE clauses. This isn't as elegant, but would still solve the problem.

### Describe alternatives you've considered

Right now, I'm writing a Lambda function using the postgres library and writing my custom queries within that. This requires me to rebuild all the connection/auth logic again (that I would otherwise get for free from the data layer). It also introduces another function that only gets called periodically meaning I have to contend with more cold starts affecting response time back to the client.

### Additional context

While I'm not certain of the decision making to not include support for `groupDefinedIn()` for custom queries, the only risk that I see would be if the query does not return the column identified in `groupDefinedIn` which should result in an error or automatic unauthorized rather than allowing it to pass through freely.

### Is this something that you'd be interested in working on?

- [ ] 👋 I may be able to implement this feature request

### Would this feature include a breaking change?

- [ ] ⚠️ This feature might incur a breaking change

Contributor guide

Open the contributing guide

Research direction

Start with the Gen2 custom query entry points shown in the issue: a.query(), a.handler.inlineSql(), and authorization with allow.groupDefinedIn(). Reproduce the gap between model authorization and custom-query authorization using the Postgres search_user procedure. Done means tenant group enforcement works for the custom query, or the database receives sufficient auth context for equivalent enforcement, with unauthorized access covered.

Written by the indexing model from the issue text.

Assessment

Tech stack
postgresql, typescript
Domain
api, databases, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.