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

[Question] Supporting external record identifiers as strings that look up non primary key #54

Open
orible opened this issue Jan 15, 2021 · 9 comments
Labels
question Further information is requested

Comments

@orible
Copy link
Contributor

orible commented Jan 15, 2021

I'll try to explain myself fully.

In my current code, I do the following when sending data to the client;

Here is the database model
image

Here is the external model being constructed from the database model
image

I use the unique UUID as the identifier when referring to it on the end client.

image

Example uID:
'90c1939d-3414-11eb-8ffe-0242ac120005'

@orible orible changed the title [Question] Supporting strings as external record identifiers instead of ID! [Question] Supporting strings as external record identifiers instead of ID Jan 15, 2021
@orible
Copy link
Contributor Author

orible commented Jan 15, 2021

So I suppose my question is;

  1. Am I able to change the schema and resolver to use the UID data as input
  2. Then use it as the first select argument to look up the record row.

@orible
Copy link
Contributor Author

orible commented Jan 15, 2021

An example of how I do it manually.

image

Notice the use of ThreadWhere.UID rather than ThreadWhere.ID

@orible orible changed the title [Question] Supporting strings as external record identifiers instead of ID [Question] Supporting external record identifiers as strings that look up non primary key Jan 15, 2021
@RichardLindhout
Copy link
Member

Not sure. We construct the id based on the type of the model + the id of the model.
e.g.

User_1

or User_2838932983298

this is to support the Node interface and Global Object Identification https://graphql.org/learn/global-object-identification/

@RichardLindhout RichardLindhout added the question Further information is requested label Jan 15, 2021
@RichardLindhout
Copy link
Member

So if I understand correctly you use internal id's and external ids?

@orible
Copy link
Contributor Author

orible commented Jan 15, 2021

Yes, mainly for security measures and the aspect of ids unique to the whole database

When making a request, the client sends back the UUID in some valid way instead of a row number

For example

GET api/v1/thread?threadId=90c1939d-3414-11eb-8ffe-0242ac120005

The record is then fetched from the thread table by this unique id, and the model ID, which is the table primary key, is then used by sqlboiler as usual for joins and such.

@RichardLindhout
Copy link
Member

Ah I see, we choose to encode the model because of the Node resolver so we know which table to fetch based on the id.

I think you could use the override converts for most of these use-cases and convert the graphql id to your internal id
https://github.com/web-ridge/gqlgen-sqlboiler#overriding-converts

@RichardLindhout
Copy link
Member

If you still have the chance I would choose between 1 id a uuid or auto increment id since gqlgen-sqlboiler does handle the unique ID across the schema . If you take security into consideration I don't know if it really would be more secure to not make your internal id's publicly https://en.wikipedia.org/wiki/Security_through_obscurity. I would recommend to put the user_id / tenant_id in your query to secure your data.

I think you will have most of the advantages if you use UUID for your id's everywhere since they are harder to guess than auto increment, so you'll still handle the 'Security through obscurity' and it's harder for users to scrape public data.

This is also interesting to read on this subject: https://softwareengineering.stackexchange.com/a/139453

We force the authentication if configured on all where's so if the user is not the owner of the object it won't do anything

dm.CommentWhere.UserID.EQ(auth.UserIDFromContext(ctx)),

https://github.com/web-ridge/gqlgen-sqlboiler-examples/blob/main/social-network/resolver.go#L71

See here more how to configure the AuthorizationScopes
https://github.com/web-ridge/gqlgen-sqlboiler-examples/blob/main/social-network/convert_plugin.go#L66

@orible
Copy link
Contributor Author

orible commented Jan 15, 2021

Aye, I do agree with the question around if it's really practical to obscure the row Ids

In terms of authentication, I'm loading a user context through information provided from access tokens, then passing the user object through the call context, and of course then asserting the user can modify the record in question in the biz logic packages.

@orible
Copy link
Contributor Author

orible commented Jan 15, 2021

As you note, the biggest reason I chose to use external ids is to prevent users from inferring the number of posts, number of users, or other such records. And of course, generally make it slightly harder to attack the api when object identifiers are opaque.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants