Skip to main content

2 posts tagged with "authentication"

View All Tags

Authentication in Exograph with Auth0

· 4 min read
Ramnivas Laddad
Co-founder @ Exograph

On the heels of Clerk integration, we are excited to announce that Exograph now supports Auth0 as an authentication provider! Exograph's JWT support seamlessly works with Auth0 out of the box. Additionally, Exograph's playground integrates Auth0's authentication UI to simplify the exploration of access control rules.

Our code will be the same as in the previous blog. Since both Clerk and Auth0 support OpenID Connect (OIDC), everything can stay the same.

context AuthContext {
@jwt("sub") id: String
}

@postgres
module TodoDatabase {
@access(self.userId == AuthContext.id)
type Todo {
@pk id: Int = autoIncrement()
title: String
completed: Boolean
userId: String = AuthContext.id
}
}

This is all the code you need for a multi-user todo app! With the rule specified in the @access annotation, each user can only query or mutate their todos.

note

Exograph's @jwt annotation works with any compliant OIDC provider, so you may use it with any other provider. However, the playground integration is currently only available with Clerk and Auth0.

To try it out, create an Auth0 project following their instructions. Pay particular attention to configuring "Allowed Callback URLs" (for this blog, you may set it to http://localhost:9876/playground, http://localhost:3000).

Then you can start the server using exo yolo with the EXO_OIDC_URL environment variable set to your Auth0 URL:

EXO_OIDC_URL=https://<your-auth0-host>.auth0.com exo yolo

This will start the server with Auth0 as the authentication provider.

Auth0 integration with Exograph Playground

A typical workflow for building an app uses the GraphQL API in the playground to try out queries and mutations needed for the frontend and copy those into the frontend code. However, in the presence of authentication, grabbing a JWT token (typically from a partially built UI) and passing it in the Authorization header can be cumbersome. Exograph Playground makes it easy to try out APIs that require authentication by integrating Auth0's UI in the playground.

Try it out. For example, you can execute the following query to get all todos:

query {
todos {
id
title
completed
}
}

If you do so without logging in, you will get an error:

{
"errors": [
{
"message": "Not authorized"
}
]
}

You can log in by clicking the "Authenticate" button in the playground. This will open Auth0's login page in the playground. You can log in using any configured provider (such as Google or Facebook). Once logged in, you can try the query again, and you will see the todos.

Similarly, you can execute mutations. For example, the following mutation will create a new todo:

mutation {
createTodo(data: { title: "Buy milk", completed: false }) {
id
}
}

Due to access control rules, you can create a todo only for the logged-in user.

Lastly, try out the query above by logging in as another user. You will see that the todos created by the first user are not visible to the second user.

Using the frontend

With the confidence that the API works as expected, building a frontend using the same queries and mutations is easy. The accompanying source code is a Next.js app that allows creating todos, marking them as completed, and updating or deleting them.

Clone the examples repository and try it out!

Summary

Combining the declarative backend of Exograph with the authentication of Auth0 is a simple matter of setting the EXO_OIDC_URL environment variable. The playground support makes it a breeze to try out various authentication scenarios to ensure that users access only the data they are supposed to.

We would love to hear your feedback on this integration on our Discord.

Share:

Fortifying Exograph with Clerk

· 6 min read
Ramnivas Laddad
Co-founder @ Exograph

In a previous blog, our code used Google Identity for authentication. While such a solution is possible, taking care of details, such as supporting multiple social providers or password-less authentication, verifying emails, and refreshing/revoking tokens, can get tedious. This is where external authentication providers such as Clerk make life easier.

Exograph now supports Clerk as an authentication provider! Our integration goes beyond supporting JWKS authentication; it also makes it easy and fun to explore APIs by integrating Clerk's UI in Exograph's playground.

This blog will transform a todo app without authentication into a multi-user todo app by adding just four lines and modifying a single line of code! The accompanying source code includes a web frontend written in Next.js, Tailwind, Apollo GraphQL Client, and TypeScript.

A taste of Clerk integration

Let's start with the same first step as the previous blog, with the code generated by the exo new command for a single-user todo project:

@postgres
module TodoDatabase {
@access(true)
type Todo {
@pk id: Int = autoIncrement()
title: String
completed: Boolean
}
}

If you start the server using exo yolo, you can explore the API in the playground to query, create, update, and delete todos.

To make this a multi-user app, we associate each Todo with a user and ensure that a user can only access their todos through the following changes:

context AuthContext {
@jwt("sub") id: String
}

@postgres
module TodoDatabase {
@access(self.userId == AuthContext.id)
type Todo {
@pk id: Int = autoIncrement()
title: String
completed: Boolean
userId: String = AuthContext.id
}
}

That's all we need to change! Compare this to other approaches where you would have to change most SQL statements or update invocation methods of an underlying framework besides including boilerplate code to deal with JWT verification.

Let's see what we did:

  • A new AuthContext sources the user id from the JWT token's sub claim (which will be the same as Clerk's user id). The client will send the JWT token in the Authorization header, and Exograph will verify it using the API URL provided by Clerk.
  • The Todo type adds a userId field. This field defaults to AuthContext's id value to let the client skip the user id when creating a todo.
  • The access control rule enforces that users may query and mutate Todos only if their userId matches AuthContext's id.
A difference from the previous blog

In the previous blog, we also had the User type, but since Clerk deals with user management, we don't need that anymore.

Now that the backend is ready, let's explore the API.

Using the playground

In a typical setup, the client will authenticate and send the Authorization token with each request. But how can you explore the API in the playground? How can you get a JWT token to put in the Authorization header? Developers often copy and paste the JWT token from the frontend app into the playground, which is a tedious process, to say the least (and requires building at least some frontend). It becomes even more challenging with providers such as Clerk, where the token expires quickly (by default, in 60 seconds).

A common problem

This is neither specific to GraphQL nor Clerk. The same issue arises with REST APIs, gRPC, etc., and any authentication mechanism, including roll-your-own.

Exograph integrates its playground with Clerk authentication (as well as roll-your-own, but that is not the focus of this blog). The playground includes the signing-in mechanism and automatically sends the Authorization header with the JWT for the signed-in user for each GraphQL request. In other words, the playground acts as an alternative frontend. You can now easily explore the API by, for example, signing in as different users and seeing how the access control rules work.

Let's try it out:

  • Set up a Clerk project by following the instructions and note down the value for "Publishable key" and "JWT public key/JWKS URL" from the Clerk dashboard under the "API Keys" section.
  • Start the Exograph server by specifying the OIDC URL as an environment variable. We will use the yolo command to start the server (you can also use the dev or production mode. See Exograph's documentation for more details).
EXO_OIDC_URL=https://<your-clerk-host>.clerk.accounts.dev exo yolo
  • In the playground, click on the key icon in the middle of the screen. The first time you open it, it will ask for the "Publishable key" you noted earlier. You may specify the template id but don't need it for this application. If you want to change this information, you can do it through the "Configure Clerk" link in the sign-in dialog.
  • You will see the sign-in dialog once you specify the publishable key.
  • Once you sign in, you will see the user's profile picture near the key icon to indicate the currently signed-in user.

Try various queries and mutations. For example, create a todo:

mutation {
createTodo(data: { title: "Buy milk", completed: true }) {
id
title
completed
}
}

Or query the todos:

query {
todos {
id
title
completed
}
}

Please see the earlier blog for a list of queries and mutations to try.

Now log out and try the same queries and mutations. You will get an error when you try to create a todo (unauthenticated users can't create todos). You will also see that you don't see any todos when you query them (users can see only their todos). Login as another user; as you would expect, you won't see the todos created by the first user.

Using the frontend

Once you have explored the API, building a frontend using the same queries and mutations is easy. The accompanying source code is a Next.js app that allows creating todos, marking them as completed, and updating or deleting them.

You can sign in as different users and see how the access control rule works (one user will not be able to see or change another user's todos).

Summary

Combining the declarative backend of Exograph with the authentication of Clerk was a breeze. It took us just four lines of code and a single-line modification to the model to make the todo app multi-user. The integration with Clerk's UI in the playground makes it easy to explore the API without building a frontend.

There is more that we didn't explore here, such as using custom templates. For example, we could use these to implement role-based access control to allow admins to see all todos. All we would have to change is add one line to the context (@jwt role: String) and modify another to add || AuthContext.role == "admin" to the access control rule! Such is the power of Exograph's declarative modeling and access control expressions. Please see the documentation for more details.

We would love to hear your feedback on this integration on our Discord.

Share: