- 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
andsqlite3
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
andbackend/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.
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
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[];
}
We also need to make sure that the index file (./src/backend/entities/sqlite/index.ts
) is updated to export this file:
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,
];
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
:
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();
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