Graphweaver Docs
  • Home
  • Github
Get Started 🚀
🗝️

Adding API Key Authentication

  • Prerequisites
  • Steps
  • Initialise a New Graphweaver Project
  • Install Dependencies
  • Get Sample Database
  • Import Database Schema
  • Create the API Key Table
  • Initialise the Authentication System
  • Define the ApiKey Entity
  • Configure Your Graphweaver Project to Use API Key Authentication
  • Apply Access Control
  • Test Your API
  • Next Steps

This guide will walk you through the process of setting up API Key authentication for your Graphweaver project. API Key authentication is a straightforward way to control access to your GraphQL API for machine-to-machine communication. This guide will also use an Sqlite database as an example data provider. Feel free to follow along or replace with your own data source as needed.

Let's get started.

Prerequisites

  • Node.js and npm/pnpm: Make sure you have Node.js 20 or above along with npm and pnpm (8+) installed on your system.
  • Some of the commands use curl and sqlite3 from the command line. These can be substituted with your own tools if you do not have them

Steps

Initialise a New Graphweaver Project

npx graphweaver@latest init
  • You'll be prompted to name your project (e.g., example ).
  • For this example choose the "Mikro-orm Sqlite backend". However, if you have a different datasource then use that.
  • Confirm the creation of the new Graphweaver app.

Install Dependencies

cd example
pnpm add @exogee/graphweaver-auth

This installs:

  • @exogee/graphweaver-auth: Core Graphweaver authentication package used in the backend.

Get Sample Database

Next, lets download the sample database:

curl -L -o database.sqlite https://github.com/lerocha/chinook-database/raw/master/ChinookDatabase/DataSources/Chinook_Sqlite.sqlite
  • This downloads a sample SQLite database named 'Chinook_Sqlite.sqlite' and renames it to 'database.sqlite'. We'll use this to store user credentials.

Import Database Schema

Next, we can introspect the database schema which will create the Graphweaver source files.

pnpm run import sqlite

What is the database name? database.sqlite
Overwrite this file backend/schema/index.ts? yes
Overwrite this file backend/database.ts? yes
  • This command analyses the SQLite database and generates TypeScript code representing its schema.
  • It overwrites existing backend/schema/index.ts and backend/database.ts files to integrate the new database structure into your Graphweaver project.

Create the API Key Table

Next, let’s add a new table to the database to store our keys:

sqlite3 ./database.sqlite "CREATE TABLE ApiKey (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    api_key VARCHAR(255) NOT NULL UNIQUE,
    secret VARCHAR(255) NOT NULL,
    revoked BOOLEAN NOT NULL DEFAULT false,
    roles TEXT NOT NULL
);"

This command uses the sqlite3 tool to create a table called 'ApiKey' in your SQLite database. This table will store the following information for each API key:

  • id: A unique identifier for the API key.
  • api_key: The actual API key that will be used in requests.
  • secret: A secret associated with the API key, typically used for additional security checks.
  • revoked: A flag indicating whether the API key has been revoked (disabled).
  • roles: A list of roles assigned to the API key, controlling its access permissions.

Initialise the Authentication System

There are a few extra configuration steps needed when setting up API Key authentication. This includes an environment variable file and the first API key. These are a bit tricky to setup at first but luckily for us there is a command line tool that can help. To run it:

pnpm graphweaver init-auth api-key
? What is the data source? sqlite
? What is the database name? database.sqlite
? Please specify the exact name of the table where you would like the data to be stored: ApiKey
  • This command sets up the authentication system within Graphweaver:
    • Generates an .env file
    • Connects to your database and creates a new random API Key, saving a hash to the database.
⚠️
The API Key that is displayed is a unique to you so make sure that you take a note of it before moving on.

Define the ApiKey Entity

Now that we have added the table in the database we need to tell Graphweaver about it. To do that open the project in your editor and navigate to the ./src/backend/entities/sqlite directory. Then create a new file ./src/backend/entities/sqlite/api-key.ts with this contents:


touch ./src/backend/entities/sqlite/api-key.ts

We also need to make sure that the index file (./src/backend/entities/sqlite/index.ts) is updated to export this file:

Configure Your Graphweaver Project to Use API Key Authentication

In order to enable password authentication in the app we need to add the following to our ./src/backend/index.ts:

This code configures your Graphweaver project to use the API key authentication system.

  • It sets up a data provider to interact with the 'ApiKey' table.
  • It defines roles that can be assigned to API keys.
  • It creates an ApiKey instance and associates it with your Graphweaver instance.

Apply Access Control

Next, we need to allow access to an entity. By default Graphweaver denies access to all entities, to change this we can allow access to the ApiKeyUsers Role to access the Album entity.

To update this navigate to the ./src/backend/schema/album.ts file and add the following code before the @entity decorator:

import { ApplyAccessControlList } from '@exogee/graphweaver-auth';

@ApplyAccessControlList({
    ApiKeyUsers: {
        all: true,
    },
})

Test Your API

Finally, we are ready to test the server. First start the server using:

pnpm start

Then we can send a test request, making sure to replace the API Key with the one that was generated earlier:

curl --location 'http://localhost:9001' \
--header 'x-api-key: RELACE_WITH_YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{"operationName":"graphweaver","variables":{},"query":"query graphweaver {\n  result: albums {\n    albumId  }\n}"}'

Congratulations, you have now configured API Key access.

Next Steps

  • Customise Roles: By default the API Key is given a role of ApiKeyUsers you can update this in the database and create your own roles as needed.
  • Permissions and Authorisation: There are currently only an ACL for the Album entity. You'll need to implement proper authorisation rules to control what different users can do in your app
Made with 💜 in Australia

Exogee

import { BigIntType, Enum, EnumArrayType, Entity, PrimaryKey, Property } from '@mikro-orm/core';
import { ApiKeyEntity } from '@exogee/graphweaver-auth';

@Entity({ tableName: 'ApiKey' })
export class ApiKey implements ApiKeyEntity<string> {
    @PrimaryKey({ type: new BigIntType('string') })
    id!: string;

    @Property({ type: String, fieldName: 'api_key' })
    key!: string;

    @Property({ type: String })
    secret!: string;

    @Property({ type: Boolean, default: false })
    revoked!: boolean;

    @Enum({ type: EnumArrayType, items: () => String, array: true, default: [] })
    roles!: string[];
}
import { Album } from './album';
import { ApiKey } from './api-key';
import { Artist } from './artist';
import { Customer } from './customer';
import { Employee } from './employee';
import { Genre } from './genre';
import { Invoice } from './invoice';
import { InvoiceLine } from './invoice-line';
import { MediaType } from './media-type';
import { Playlist } from './playlist';
import { Track } from './track';

export * from './album';
export * from './api-key';
export * from './artist';
export * from './customer';
export * from './employee';
export * from './genre';
export * from './invoice';
export * from './invoice-line';
export * from './media-type';
export * from './playlist';
export * from './track';

export const entities = [
	Album,
	ApiKey,
	Artist,
	Customer,
	Employee,
	Genre,
	Invoice,
	InvoiceLine,
	MediaType,
	Playlist,
	Track,
];
import Graphweaver from '@exogee/graphweaver-server';
import { ApiKey } from '@exogee/graphweaver-auth';
import { MikroBackendProvider } from '@exogee/graphweaver-mikroorm';

import { ApiKey as OrmApiKey } from './entities/sqlite';
import { connection } from './database';
import { graphweaverMetadata } from '@exogee/graphweaver';

import './schema';

export const apiKeyDataProvider = new MikroBackendProvider(OrmApiKey, connection);

export enum Roles {
    API_KEY_USER = 'ApiKeyUsers',
}

graphweaverMetadata.collectEnumInformation({
    name: 'Roles',
    target: Roles,
});

export const apiKey = new ApiKey<string>({
    provider: apiKeyDataProvider,
    acl: {},
    roles: Roles,
});

export const graphweaver = new Graphweaver();
export const handler = graphweaver.handler();