# Technical Documentation: nhost/docs

> ℹ️ **Provenance:** Hybrid Fusion: `nhost/docs` + `nhost/docs` · [CodeWiki Reference](https://codewiki.google/github.com/nhost/docs) · Recency: Active (< 180 days)

## 1. Project Overview & Quickstart (nhost/docs)

## Deprecation notice
the source code of the NHost documentation moved to the main [nhost/nhost repository](https://github.com/nhost/nhost).

## 2. Official Technical Reference & Guides (nhost/docs)

## File: README.md

## Deprecation notice
the source code of the NHost documentation moved to the main [nhost/nhost repository](https://github.com/nhost/nhost).

---

## File: jsconfig.json

{
  "compilerOptions": {
    "baseUrl": "./src"
  }
}

---

## File: package.json

{
  "name": "docs",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "export": "next export",
    "start": "next start"
  },
  "dependencies": {
    "@mdx-js/loader": "^1.6.22",
    "@mdx-js/react": "^1.6.22",
    "@next/mdx": "^9.4.4",
    "autoprefixer": "^10.2.4",
    "classnames": "^2.2.6",
    "mdx-prism": "https://github.com/doamatto/mdx-prism",
    "next": "^11.1.0",
    "next-mdx-enhanced": "^5.0.0",
    "next-seo": "^4.7.3",
    "next-themes": "^0.0.14",
    "postcss": "^8.2.10",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-medium-image-zoom": "^4.3.1",
    "rehype": "^11.0.0",
    "remark-code-titles": "^0.1.1",
    "remark-unwrap-images": "^2.0.0",
    "smartlook-client": "^4.6.1"
  },
  "devDependencies": {
    "postcss-preset-env": "^6.7.0",
    "tailwindcss": "^2.0.3",
    "webpack": "^5.28.0",
    "webpack-cli": "^4.5.0"
  }
}

---

## File: src/pages/index.mdx

---
title: "Welcome to Nhost"
publishedAt: "2020-07-29"
---

Nhost is a full-fledged serverless backend for Jamstack and client-serverless applications. It enables developers to build dynamic websites without having to worry about infrastructure, data storage, data access and user management.

Nhost was inspired by [Google Firebase](https://firebase.google.com/), but uses **SQL**, **GraphQL** and has **no vendor lock-in**.

## Get started

If you are new to Nhost we recommend the [quick start guide](/quick-start). You will learn the basic concepts with Nhost and build a Todo-app with react.

## Discover Nhost

Every Nhost project is a production ready backend:

### PostgreSQL

PostgreSQL is the world's most advanced open-source relational database. Your data will be instantly accessible over GraphQL and any modification to your database instance can be done through the Hasura console.

### Hasura

Hasura provides access to your data layer through an instant realtime GraphQL API based on your PostgreSQL database. Managing your data, schemas, permissions, event triggers, remote schemas, etc is done through the Hasura console.

### GraphQL

A realtime GraphQL API with full CRUD capabilities is instantly available.

### Authentication

Register, login and manage users. Either with email and password or via external OAuth providers such as GitHub, Google, Facebook, etc. All users are stored in a `users` table.

### Storage

Let users upload and download files. Control what users are allowed to read/write using storage security rules. All files are stored in a MinIO S3 server which you also have direct access to.

### Open Source

All software in a Nhost project is **open-source**. This means **no vendor lock-in**.

### GitHub integration

Connect your GitHub repository to your Nhost project. Push changes for automatic deployment to production.

---

## File: src/pages/auth/api-reference.mdx

---
title: "API Reference for Nhost Authentication"
---

## User

| Endpoint                                    | Method | Description           |
| ------------------------------------------- | ------ | --------------------- |
| [/auth/register](#register-user)            | POST   | Register user         |
| [/auth/login](#login-user)                  | POST   | Login user            |
| [/auth/logout](#logout-user)                | POST   | Logout user           |
| [/auth/activate](#activate-user)            | POST   | Activate user         |
| [/auth/token/refresh](#refresh-token)       | GET    | Get new refresh token |
| [/auth/token/revoke](#revoke-refresh-token) | POST   | Revoke refresh token  |
| [/auth/delete](#delete-user)                | POST   | Delete user           |

## Password

| Endpoint                                                     | Method | Description                  |
| ------------------------------------------------------------ | ------ | ---------------------------- |
| [/auth/change-password/](#change-password)                   | POST   | Change password as logged in |
| [/auth/change-password/request](#request-to-change-password) | POST   | Request to change password   |
| [/auth/change-password/change](#change-password-with-ticket) | POST   | Change password with ticket  |

## Email

| Endpoint                                               | Method | Description               |
| ------------------------------------------------------ | ------ | ------------------------- |
| [/auth/change-email/](#change-email-as-logged-in)      | POST   | Change email as logged in |
| [/auth/change-email/request](#request-to-change-email) | POST   | Request to change email   |
| [/auth/change-email/change](#change-email-with-ticket) | POST   | Change email with ticket  |

## MFA (Multi-Factor Authentication)

| Endpoint                                    | Method | Description          |
| ------------------------------------------- | ------ | -------------------- |
| [/auth/mfa/generate](#generate-mfa-qr-code) | POST   | Generate MFA QR-code |
| [/auth/mfa/enable](#enable-mfa)             | POST   | Enable MFA           |
| [/auth/mfa/disable](#disable-mfa)           | POST   | Disable MFA          |
| [/auth/mfa/totp](#totp-login)               | POST   | TOTP login           |

## Register user

Register a new user.

### nhost-js-sdk

```js
auth.register({ email, password });
```

With custom user_data, for ex `display_name`:

```js
auth.register({
  email,
  password,
  options: {
    userData: {
      display_name: "Joe Doe",
    },
  },
});
```

### Request

`POST /auth/register`

```json
{
  "email": "elon@tesla.com",
  "password": "password"
}
```

With custom user_data, for ex `display_name`:

```json
{
  "email": "elon@tesla.com",
  "password": "password",
  "user_data": {
    "display_name": "Elon Musk"
  }
}
```

### Response

```json
{
  "session": {
    "jwt_token": "e3MmYZSJdLCJ4LWhhjE0MDg3Nzc3fQ.d4kdsiBjD3MpPpbNNbaMt-gyHHVXwrSvrAtVcEQ_jB8",
    "jwt_expires_in": 900000,
    "user": {
      "id": "kcf72f45-5a2d-4615-810d-96e10548bb35",
      "display_name": "nuno@nhost.io",
      "email": "nuno@nhost.io"
    },
    "refresh_token": "dd69aafd-71f6-4f97-be93-9bdbfb192fe6"
  },
  "user": {
    "id": "kcf72f45-5a2d-4615-810d-96e10548bb35",
    "display_name": "nuno@nhost.io",
    "email": "nuno@nhost.io"
  }
}
```

> If `AUTO_ACTIVATE_NEW_USERS` is `false`, `session` will return `null`.

---

## Login user

Login user

### nhost-js-sdk

```js
auth.login({ email, password });
```

### Request

`POST /auth/login`

```json
{
  "email": "marc@facebook.com",
  "password": "password"
}
```

### Response

```bash
Set-Cookie: refresh_token=...
Set-Cookie: permission_variables=...
```

```json
{
  "session": {
    "jwt_token": "e3MmYZSJdLCJ4LWhhjE0MDg3Nzc3fQ.d4kdsiBjD3MpPpbNNbaMt-gyHHVXwrSvrAtVcEQ_jB8",
    "jwt_expires_in": 900000,
    "user": {
      "id": "kcf72f45-5a2d-4615-810d-96e10548bb35",
      "display_name": "nuno@nhost.io",
      "email": "nuno@nhost.io"
    },
    "refresh_token": "dd69aafd-71f6-4f97-be93-9bdbfb192fe6"
  },
  "user": {
    "id": "kcf72f45-5a2d-4615-810d-96e10548bb35",
    "display_name": "nuno@nhost.io",
    "email": "nuno@nhost.io"
  }
}
```

If Multi-Factor Authentication (MFA) is enabled for the account, the following response body is returned:

```json
{
  "session": null,
  "user": null,
  "mfa": {
    "ticket": "762ea295-4a12-436f-b8fc-36b91aefb28e"
  }
}
```

For login with MFA, proceed authentication by requesting the [TOTP /auth/mfa/totp](#totp-login) endpoint.

---

## Logout user

Logout user.

### nhost-js-sdk

```ts
auth.logout(all: boolean = false);
```

### Request

`POST /auth/login?all=`

if `all = true` all of the user's refresh token will be revoked from the database, effectevly logging out the user from all devices. If `all = false` only the current refresh token will be deleted and the user will only logout from the current device. `all` is optional and defaults to `false`.

### Response

```json
{
  "session": null,
  "user": null
}
```

---

## Activate user

Activate user.

This is only needed if users is not automatically activated. If users are not automatically activated Nhost will send an email, containing the activation URL, to the user to activate their account. The [email template for account activate](/auth/email-templates#activate-account) can be edited.

### nhost-js-sdk

```ts
auth.activate(ticket: string);
```

### Request

`POST /auth/activate?ticket=<ticket>`

### Response

```json
204 No Content
```

---

## Get refresh token

When a user login Nhost will set a refresh-token as a cookie. That refresh-token is used to request a new JWT-token, since JWT-tokens are short lived (15 min). Refresh-tokens are long lived (1 year).

The refresh-token cookie is a `Secure` `HttpOnly` cookie and can not be accessed by the browser because only Nhost should be able to read the cookie.

### nhost-js-sdk

[`nhost-js-sdk`](/libraries/nhost-js-sdk) automatically handle refreshing-tokens for logged in users in the background. No action required.

### Request

`GET /auth/token/refresh`

```bash
Cookie: refresh_token=<current_refresh_token>
```

### Response

```bash
Cookie: refresh_token=<new_refresh_token>
```

```json
{
  "session": {
    "jwt_token": "e3MmYZSJdLCJ4LWhhjE0MDg3Nzc3fQ.d4kdsiBjD3MpPpbNNbaMt-gyHHVXwrSvrAtVcEQ_jB8",
    "jwt_expires_in": 900000,
    "user": {
      "id": "kcf72f45-5a2d-4615-810d-96e10548bb35",
      "display_name": "nuno@nhost.io",
      "email": "nuno@nhost.io"
    },
    "refresh_token": "dd69aafd-71f6-4f97-be93-9bdbfb192fe6"
  },
  "user": {
    "id": "kcf72f45-5a2d-4615-810d-96e10548bb35",
    "display_name": "nuno@nhost.io",
    "email": "nuno@nhost.io"
  }
}
```

---

## Revoke refresh-token

Revoke a refresh-token.

### nhost-js-sdk

_not implemented_

### Request

`GET /auth/token/refresh`

```bash
Cookie: refresh_token=<current_refresh_token>
```

### Response

```bash
204 No Content
```

---

## Delete user

Used so user can delete themselves. This will delete the user in the `users` table which will cascade and delete all associated data for the particular user if `ON DELETE CASCADE` is set for Foreign keys.

This endpoint is only active if you allow users to delete themselves in **Settings -> Authentication**. (Not implemented yet, default value is **Not active**)

### nhost-js-sdk

_not implemented_

### Request

`POST /auth/delete`

```bash
Set-Cookie: refresh_token=...
Set-Cookie: permission_variables=...
```

### Response

```bash
204 No Content
```

---

## Change password

For users to change their password when they are logged in and remember their previous password.

### nhost-js-sdk

```ts
auth.changePassword(oldPassword: string, newPassword: string);
```

### Request

`POST /auth/change-password`

```bash
Set-Cookie: refresh_token=...
Set-Cookie: permission_variables=...
```

```json
{
  "old_password": "<old password>",
  "new_password": "<new password>"
}
```

### Response

```bash
204 No Content
```

---

## Request to change password

If a user has forget their password they can request to change their password.

An email will be sent out to the user with a `ticket` that should be used to update the user's password. You can change the [password reset email template](/auth/email-templates#password-reset).

### nhost-js-sdk

```ts
auth.requestPasswordChange(email: string);
```

### Request

`POST /auth/change-password/request`

```json
{
  "email": "<user's email>"
}
```

### Response

```bash
204 No Content
```

> This endpoint will always return HTTP status code 204 in order to not leak information about the database.

---

## Change password with ticket

Change password with ticket from the email.

### nhost-js-sdk

```ts
auth.confirmPasswordChange(newPassword: string, ticket: string);
```

### Request

`POST /auth/change-password/change`

```json
{
  "new_password": "<new password>",
  "ticket": "<ticket>"
}
```

### Response

```bash
204 No Content
```

## Generate MFA QR-code

Generate MFA (Multi-Factor Authentication) QR-code. The user must be logged in to generate this QR-code. The user should scan the QR-code with their password manager. The password manager will return a `code` (one-time password) that will be used to [enable](#enable-mfa) and [disable](#disable-mfa) MFA for the user and login the user using [TOTP login](#totp-login).

### nhost-js-sdk

```ts
auth.MFAGenerate(code: string, ticket: string);
```

### Request

`POST /auth/mfa/generate`

### Response

```json
{
  "image_url": "<base64 data image of the qe code>",
  "otp_secret": "<otp secret>"
}
```

---

---

## Enable MFA

Enable MFA (Multi-Factor Authentication). Use the `code` (one-time password) in the user's password manager

### nhost-js-sdk

```ts
auth.MFAEnable(code: string);
```

### Request

`POST /auth/mfa/enable`

```json
{
  "code": "123456"
}
```

### Response

```bash
204 No Content
```

---

## Disable MFA

Disable MFA (Multi-Factor Authentication). Use the `code` (one-time password) in the user's password manager

### nhost-js-sdk

_Not implemented yet_

### Request

`POST /auth/mfa/disable`

```json
{
  "code": "code from mfa client"
}
```

### Response

```bash
204 No Content
```

---

## TOTP login

**T**ime-based **O**ne-**T**ime **P**assword login. Use the `ticket` from [Login](#login-user) response body and the `code` from the user's password manager.

### nhost-js-sdk

```ts
auth.MFATotp(code: string, ticket: string);
```

### Request

`POST /auth/mfa/generate`

### Response

```json
{
  "image_url": "<base64 data image of the qe code>",
  "otp_secret": "<otp secret>"
}
```

---

---

## File: src/pages/auth/custom-user-columns.mdx

---
title: "Custom user columns"
---

You can add any custom columns to the `users` table.

> Don't remove any predefined user columns.

## JWT claims

All custom columns on the `users` table can be added to the JWT-token as claims. These claims can then be used to set [Hasura permissions](/hasura/permissions).

As an example, let's say you have a `company` table and a `company_id` column to the `users` table. With that, you can now add `company_id` as an `x-hasura-company-id` key to your JWT claims.



The new JWT-token contains the `company_id` as `x-hasura-company-id`.

```json
{
  "https://hasura.io/jwt/claims": {
    "x-hasura-user-id": "f1126a1e-49e8-47b9-b9cc-e6dd5d568c7e",
    "x-hasura-allowed-roles": ["user", "me"],
    "x-hasura-default-role": "user",
    "x-hasura-company-id": "b3b70430-49db-4c06-b365-efb498e59913"
  },
  "iat": 1595247544,
  "exp": 1595247844
}
```

`x-hasura-company-id` can now be used as a permission variable for Hasura permissions.

In the example below, a user is allowed to select information about their own company (id = `x-hasura-company-id`).



## Set user field data on registration

You can specify what user fields that can be set during registration under **Settings -> Authentication -> REGISTRATION CUSTOM FIELDS**.

A popular field to let users set during registration is `display_name` that exist on the `users` table by default.

With [`nhost-js-sdk`](/libraries/nhost-js-sdk) you can register a user, with the `display_name` like this:

```js
import { auth } from "utils/nhost";

const email = "elon@tesla.com";
const password = "123123";
const displayName = "Elon Musk";

auth.register({
  email,
  password,
  options: {
    userData: {
      display_name: displayName,
    },
  },
});
```

---

## File: src/pages/auth/email-templates.mdx

---
title: "Email templates"
---

## Activate Account Email Template

This email is sent to new users to activate their account. Use the `url` and `ticket` variables (`[Activate your account]({{ url }}/auth/activate?ticket={{ ticket }})`) to let users activate their account.

This email is sent **only if** the setting **User registration auto active is off** and **Require to verify new emails when user change email is on**.

Change those settings under **Settings -> Auth** in the Nhost console.

### Variables

- `display_name` - user's display name.
- `ticket` - UUID token to activate the user's account.
- `url` - Backend server URL, usually `https://backend-xxx.nhost.app`.

---

## Password Reset Email Template

Email to users requesting to change their password, usually because the user has forgot their current password.

The URL in this email should go to your app with a form to change the user's password. Use the ticket to authenticate the [password change request](https://nhost.github.io/hasura-backend-plus/api.html#change-password-change).

### Variables

- `ticket` - UUID token to change password.

---

## Change Email Email Template

Email for users requesting to change their current email. This email is sent to the new email address the user wants to change to, in order to confirm the new email address.

The URL in this email should go to your app. Your app should receive the ticket and [change the email](https://nhost.github.io/hasura-backend-plus/api.html#change-email-change).

### Variables

- `ticket` - UUID token used to change email.

---

## How To Use Variables in Email Templates

Use variables in email-templates with curly brackets.

```html
<p>Hi {{ display_name }}</p>
<p>
  <a href="{{ url }}/auth/activate?ticket={{ ticket }}">
    Activate your account
  </a>
</p>
```

## SMTP Settings

By default, all emails are sent with Nhost's SMTP settings from `nhost.app` using [Sendgrid](https://sendgrid.com/). You can change the SMTP settings to your own at **Settings -> SMTP**.

## More Settings

### Verify emails

Send emails to verify (activate) a new account and verify a new email a user whish to change to.

If Verify emails is disabled, Nhost won't send an activation email to new users nor send emails when a user whish to change their email. For user activation, you need to handle that your self (if you don't automatically activate new users). For email change, the email will be changed instantly with out verification.

### HIBP

If activated, passwords will be checked against [HIBP (haveibeenpwned.com)](https://haveibeenpwned.com/). Weak and compromised passwords will not be accepted.

---

## File: src/pages/auth/index.mdx

---
title: "Nhost Authentication"
---

Your app probably needs a way to authenticate users. That's easy with Nhost.

Nhost Authentication integrates tightly with other services in your Nhost project, such as [Hasura](/hasura) and [Storage](/storage).

You can log in users with:

- Email / Password
- Github
- Google
- Facebook
- Linkedin

For easy integration with auth (and storage) in your app, use [nhost-js-sdk](/libraries/nhost-js-sdk).

## Tokens

Nhost Authentication uses **JWT-tokens and refresh-tokens**. **A JWT token** is used in a GraphQL API request to authenticate the user and to resolve [Hasura permissions](/hasura/permissions). **A refresh tokens** is used to request new JWT-token.

**A JWT-token can not be revoked**; they can only expire. Because of that, JWT tokens are short-lived (15 min). Before a JWT-token expires, the client should request a new JWT-token using the refresh token. **A refresh token can be revoked** and is long-lived (1 year). To revoke a refresh-token, remove the refresh-token from the database in the `auth.refresh_tokens` table.

You can configure the expiration time for both JWT-tokens and refresh-tokens in the Nhost console under **Settings -> Authentication**.

By default, each JWT-token includes the user's **id** and **roles** as _claims_. Here's an example:

```json
{
  "https://hasura.io/jwt/claims": {
    "x-hasura-allowed-roles": ["user", "me"],
    "x-hasura-default-role": "user",
    "x-hasura-user-id": "c8ee8353-b886-4530-9089-631ea7fd4c8a"
  },
  "iat": 1595146465,
  "exp": 1595147365
}
```

You can add more claims to the JWT token using [custom user columns](/auth/custom-user-columns).

---

## File: src/pages/auth/local-users.mdx

---
title: "Local users"
---

The easiest way for users to signup is using **email and password**. All users are stored in the `users` table, and relevant account information is saved in the tables under the `auth` schema.

Passwords are hashed using [bcrypt](https://www.npmjs.com/package/bcrypt) with multiple salt rounds.

## Quick Start

The easiest way to register and login users is with [nhost-js-sdk](/libraries/nhost-js-sdk).

### Install

`npm install --save nhost-js-sdk`

### Setup

In ex `/src/utils/nhost.js`:

```js
import { createClient } from "nhost-js-sdk";

const config = {
  baseURL: "https://backend-REPLACE.nhost.app",
};

const { auth, storage } = createClient(config);

export { auth, storage };
```

### Usage

Register a user:

```js
import { auth } from "utils/nhost";

const email = "elon@tesla.com";
const password = "123123";

auth.register({ email, password });
```

Login user:

```js
import { auth } from "utils/nhost";

const email = "elon@tesla.com";
const password = "123123";

auth.login({ email, password });
```

Learn more about the [`nhost-js-sdk`](/libraries/nhost-js-sdk).

Learn more about the [Auth API Reference](/auth/api-reference).

## Manage users

All users are manageable in the Nhost console in the **Auth** tab.

---

## File: src/pages/auth/multi-factor-authentication.mdx

---
title: "Multi-Factor Authentication (MFA)"
---

Multi-Factor Authentication (MFA), also called Two-Factor Authentication (2FA) improves login security for users.

Nhost uses [Time-based One-time Password algorithm](https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm) (TOTP) for MFA.

If MFA is enabled, a user must both use email/password and a **T**ime-based **O**ne-**T**ime **P**assword (TOPT) to be able to login.

By default, users has MFA disabled.

## How to enable for a user:

- [Generate MFA QR code](/auth/api-reference#generate-mfa-qr-code)
- Scan MFA QR code with password manager
- Get a `code` (one-time password) from password manager
- Use `code` to [enable MFA](/auth/api-reference#enable-mfa).

## How to disable MFA for a user

- Get a `code` (one-time password) from password manager
- Use `code` to [disable MFA](/auth/api-reference#disable-mfa).

## How to login when MFA is enabled

- Login using email and password
- Save `ticket` response from the login
- Copy `code` one-time password from password manager
- Send `ticket` and `code` to [TOTP login](/auth/api-reference#totp-login)
- User is logged in.

---

## MFA clients

If you have a password manager there is usually built-in support for MFA.

You can also use a stand-alone MFA client such as [Google Authenticator](https://support.google.com/accounts/answer/1066447).

---

## File: src/pages/auth/roles.mdx

---
title: "Roles"
---

Each user can have one or more roles. By default, each user has the roles `user` and `me`.

A role is used to set [Hasura Permissions](/hasura/permissions) and [Storage Security Rules](/storage/security-rules).

A user's roles are defined in the JWT-token that is automatically generated when a user logs in.

Here's an example:

```json
{
  "https://hasura.io/jwt/claims": {
    "x-hasura-allowed-roles": ["user", "me"],
    "x-hasura-default-role": "user",
    "x-hasura-user-id": "c8ee8353-b886-4530-9089-631ea7fd4c8a"
  },
  "iat": 1595146465,
  "exp": 1595147365
}
```

## Default role

The `x-hasura-default-role` claim is the **default role** of the user. This role is used for every request unless you change the role manually during the request (See [Change role in a GraphQL request](#change-role-in-a-graphql-request)). By default the default role is `user`.

## Allowed roles

A user can have multiple allowed roles. Allowed roles are roles that the user can use to make a GraphQL request. A GraphQL request can only use **one** role per request.

## Me role

The `me` role can be used to set user specific permission for the own user. For example, you might want to allow all users (`user` role) to select `id` and `display_name` for all users in your app. But each user should also be able to see their own `birthday`. You can use the `me` role to select the `birthday`.

## Change role in a GraphQL request

A user can override the default role in a GraphQL API request by setting the `x-hasura-role` header. The new role **must** be in the `x-hasura-allowed-roles` array.

As an example, let's say a user has the roles `user`, `me` and `editor`:

```bash
x-hasura-default-role: user
x-hasura-allowed-roles: ["user", "me", "editor"]
```

Then the user can make a request as an editor like this:

```jsx
const { loading, error, data } = useQuery(MY_QUERY, {
  context: {
    headers: {
      "x-hasura-role": "editor",
    },
  },
});
```

## Default allowed user roles

A user can have multiple default roles directly on registration. The default allowed user roles can be set in **Settings -> Authentication -> DEFAULT ALLOWED ROLES**.

## Public role

If a user is not logged-in and no header or token is sent with the GraphQL request, Hasura resolves the request using the `public` role.

> HASURA_GRAPHQL_UNAUTHORIZED_ROLE is set to `public` by default for all Nhost projects.

---

## File: src/pages/auth/oauth-providers/facebook.mdx

---
title: "Facebook OAuth"
---

Here is a guide on how to set up OAuth with Facebook:

[https://developers.facebook.com/docs/facebook-login/](https://developers.facebook.com/docs/facebook-login/)

---

## File: src/pages/auth/oauth-providers/github.mdx

---
title: "Github OAuth"
---

To enable Github as a Auth provider you must first create an OAuth App in [Github](http://github.com/). On Github, go to **Settings > Developer settings > OAuth apps** and click **New OAuth App**.



Set a name, a homepage URL and the Authorization callback URL. The Authorization callback URL you should use is inside the Nhost console under **Settings > Sign-methods > Github** (see last image).



The Github OAuth app is now created. Finally create a **Client Secret**. Copy both **Client ID** and **Client Secret** and insert them in the Nhost console and click **Save**.





Your app is now configured with Github and users can now register and sign in with Github.

To register users, simply direct them to `https://backend-REPLACE.nhost.app/auth/providers/github`.

Example:

```html
<a href="https://backend-REPLACE.nhost.app/auth/providers/github">
  Sign in with Github
</a>
```

---

## File: src/pages/auth/oauth-providers/google.mdx

---
title: "Google OAuth"
---

Here is a guide on how to set up OAuth with Google:

[https://support.google.com/cloud/answer/6158849](https://support.google.com/cloud/answer/6158849)

---

## File: src/pages/auth/oauth-providers/index.mdx

---
title: "OAuth overview"
---

With Nhost, it's easy to sign in users with external OAuth providers. OAuth providers are configured in the Nhost console at **Settings -> Sign-in methods**.

## Supported OAuth providers

- Github
- Google
- Facebook
- LinkedIn

## Redirect URLs

You must first set the auth redirect URLs to start using an OAuth provider. The redirect URL specifies where your users should return to once the signup/signin is complete.



> If you develop locally, set the Redirect URLs to your local web app. Ex http://localhost:3000.

## How to sign up and sign in users

The flow for both signup and signin is the same. Link to `https://backend-REPLACE.nhost.app/auth/providers/[provider]` in your signup/signin page.

> `[provider]` can be one of `github`, `google`, `facebook`, `linkedin`.

---

## File: src/pages/auth/oauth-providers/linkedin.mdx

---
title: "LinkedIn OAuth"
---

Here is a guide on how to set up OAuth with LinkedIn:

[https://www.linkedin.com/developers/apps/new](https://www.linkedin.com/developers/apps/new)

Note that you need to add **Sign In with LinkedIn** as a product under **Products**.

---

## File: src/pages/cli/deploy.mdx

---
title: "Nhost Deploy"
---

Deploy pushes your local changes to your production Nhost project

```bash
$ nhost deploy

✔ migrations deployed

✔ metadata deployed
```

All the local changes should now be reflected in production.

### Deploy using Git

If the repository is connected to the Nhost project deployment will happen automatically on push to the `master` or the `main` branch.

---

## File: src/pages/cli/dev.mdx

---
title: "Nhost Dev"
---

## Nhost Dev

`nhost dev` starts your local development environment.

```bash
$ nhost dev

⠇ Nhost is starting...

# The first time dev is run takes a bit longer because the database is being created

✔ Local Nhost backend is running!
GraphQL API:	http://localhost:8080/v1/graphql
Hasura Console:	http://localhost:9695
Auth & Storage:	http://localhost:9000
API:			http://localhost:4000
```

> The local websocket url is `ws://localhost:8080/v1/graphql`

Great! You now have a Nhost backend locally with all services:

- PostgreSQL
- Hasura GraphQL Engine
- Hasura Backend Plus
- Custom API

The Hasura console (`http://localhost:9695`) was launched. Use this URL specifically to make changes in Hasura to track migrations and metadata automatically (recommended). All metadata and migrations are stored in the `nhost/` folder.

## Logs

Get local logs for each service when you develop locally.

### PostgreSQL

```bash
$ docker logs -f nhost_postgres
```

### Hasura GraphQL Engine

```bash
$ docker logs -f nhost_hasura
```

### Hasura Backend Plus

```bash
$ docker logs -f nhost_hbp
```

### Custom API

```bash
$ docker logs -f nhost_api
```

## Configuration

> Note that for the below configurations to take effect, you need to restart `nhost dev`.

### Permission variables

To add permission variables to the JWT token set `JWT_CUSTOM_FIELDS` in `.env.development`.

Example: if every user has a `company_id` column that should be used as a permission variable in the JWT token (`x-hasura-company-id`):

```bash:.env.development
JWT_CUSTOM_FIELDS=company_id
```

### Registration custom fields

To add registration custom fields set `REGISTRATION_CUSTOM_FIELDS` in `.env.development`

Example: If users should be able to set `display_name` on registration.

```bash:.env.development
REGISTRATION_CUSTOM_FIELDS=display_name
```

## Networking

The docker containers all expose their ports directly on the host machine, so you can both reach them on localhost as well as on the host machine IP address from another machine connected to the same network (if firewall rules allows).

### Expo

In Expo, to make development use the dev environment both in the simulator and in Expo Go and production use production, see code below:

```
export const URL =
  Constants.manifest.packagerOpts.dev && !Constants.isDevice
    ? "http://localhost:9001"
    : typeof manifest.packagerOpts === `object` && manifest.packagerOpts.dev
    ? `http://${manifest.debuggerHost.split(`:`).shift().concat(`:9001`)}`
    : "nhost.io cloud url";
```

---

## File: src/pages/cli/down.mdx

---
title: "Nhost down"
---

`nhost down` stops and removes the local Nhost backend and can be used if the local Nhost backend was not shut down properly using ctrl + c with `nhost dev`.

```bash
$ nhost down


All Nhost services down
```

---

## File: src/pages/cli/env-ls.mdx

---
title: "Nhost env:ls"
---

`nhost env:ls` lists all dev environment variables.

```bash
$ nhost env:ls
Environment variables for todos-cli.

name                value (dev)
FIRST_ENV           22
ANOTHER_ONE         myAPIkey
```

---

## File: src/pages/cli/env-pull.mdx

---
title: "Nhost env:pull"
---

`nhost env:pull` pulls all dev environment variables to the local environment making the project's dev environment variables available in Hasura and in the Custom API.

```bash
$ nhost env:pull
Overwriting existing .env.development file
Downloading development environment variables for project: todos-cli
✅  .env.development file updated
```

---

## File: src/pages/cli/index.mdx

---
title: "Nhost CLI (beta)"
---

The CLI is your primary interface when doing local development.

## Install

```bash
$ npm install -g nhost
```

## Dependencies

The [Hasura CLI](https://hasura.io/docs/1.0/graphql/core/hasura-cli/install-hasura-cli.html#install-hasura-cli), [Docker](https://docs.docker.com/get-docker/) and [Docker Compose](https://docs.docker.com/compose/install/) are dependencies, please make sure to have those installed.

### Hasura CLI version

Make sure you have at least the version of your Hasura version on Nhost. You can see your Hasura version on Nhost under Settings -> Hasura -> Hasura Version.

Check Hausra CLI

```bash
$ hasura version
```

Update your Hasura CLI:

```bash
$ hasura update-cli --version [version]
```

You can find Hasura's releases on their [GitHub release page](https://github.com/hasura/graphql-engine/releases).

You might also need to update the cli-ext plugin:

```bash
$ hasura plugins cli-ext upgrade --version [version]
```

> Since version Hasura version [v2.0.0-alpha.5](https://github.com/hasura/graphql-engine/releases/tag/v2.0.0-alpha.5) the **cli-ext** plugin is a native part of the Hasura CLI and is no longer needed as a plugin.

## Usage

```bash
USAGE
  $ nhost [COMMAND]

COMMANDS
  deploy  Deploy local migrations to Nhost production
  dev     Start Nhost project for local development
  help    display help for nhost
  init    Initialize current working directory with a Nhost project
  login   Login to your Nhost account
  logout  Logout from your Nhost account
```

## Workflow

```bash
# login to your Nhost account
$ nhost login

# initialize working directory as a Nhost project
# please make sure to run it at the root of your project
$ nhost init

# start your development environment (Hasura, HBP, Postgres and Minio)
# Make sure Docker is already running on your machine.
$ nhost dev
```

## Beta

The CLI is still in beta, so please feel free to send us feedback, bug reports, and issues through the project's [repo](https://github.com/nhost/cli).

---

## File: src/pages/cli/init.mdx

---
title: "Nhost Init"
---

## Nhost Init

`nhost init` initializes a project for local development. Here we are going to initialize a project called `todos-cli`.

> `nhost init` does not yet work on Windows. Follow the [GitHub issue](https://github.com/nhost/cli/issues/18).

```bash
$ nhost init
? Select Project (Use arrow keys)
  ---personal---
❯ todos-cli

# Enter to choose the project to initialize

⠇ Initializing todos-cli
Nhost project successfully initialized
```

Let's now look at some of the configuration created.

```bash
tree .
.
└── nhost
    ├── config.yaml
    ├── metadata
    │   ├── actions.graphql
    │   ├── actions.yaml
    │   ├── allow_list.yaml
    │   ├── cron_triggers.yaml
    │   ├── functions.yaml
    │   ├── query_collections.yaml
    │   ├── remote_schemas.yaml
    │   ├── tables.yaml
    │   └── version.yaml
    ├── migrations
    │   └── 1605871545375_init
    │       └── up.sql
    └── seeds
        └── 1605871559317_roles_and_providers.sql

5 directories, 12 files
```

The `config.yaml` file is where versions and ports can be defined for each service. The versions specified by default are the same running in the production project.

```bash
cat nhost/config.yaml
# hasura configuration for the CLI
version: 2
metadata_directory: metadata

# hasura configuration for the project
hasura_graphql_version: v1.3.0.cli-migrations-v2
hasura_graphql_port: 8080
hasura_graphql_admin_secret: 123456

# hasura backend plus configuration
hasura_backend_plus_version: v2.2.0
hasura_backend_plus_port: 9000

# postgres configuration
postgres_version: 12.0
postgres_port: 5432
postgres_user: postgres
postgres_password: postgres

# custom environment variables for Hasura GraphQL engine: webhooks, headers, etc
env_file: ../.env.development
```

Also relevant here, is the init migration that creates a snapshot of the current schema pulled from the project `todos-cli` and the seeds file which populates the local database with data for both the roles and providers tables used for authentication purposes.

---

## File: src/pages/cli/link.mdx

---
title: "Nhost Link"
---

`nhost link` links an existing directory with an existing Nhost project. Usually after you've cloned a git repository.

```bash
$ nhost link
? Select Project (Use arrow keys)
  ---personal---
❯ todos-cli
Project linked: todos-cli
```

Once the local directory is linked with a Nhost project, the commands [`nhost env:ls`](/cli/env:ls) and `nhost env:pull` are available.

---

## File: src/pages/cli/login.mdx

---
title: "Nhost Login"
---

`nhost login` allows us to log in to our accounts so that projects associated with them are available to be initialized and started.

```bash
nhost login
Enter your email: nunopato@gmail.com

✔ Email sent to nunopato@gmail.com, please follow the instructions within it

⠼ Waiting for your confirmation

# Check your inbox and follow the instructions

✔ Email Confirmed! You are now logged in.
```

A corresponding `nhost logout` account is also available.

---

## File: src/pages/custom-api/index.mdx

---
title: "Custom API (beta)"
---

Deploy a custom API on Nhost. Also called: Lambda, Serverless Functions, Cloud Functions etc.

To deploy the custom API you must:

1. Init your project with the [nhost-cli](https://docs.nhost.io/cli): `nhost init`
2. Connect your repository to your Nhost project under Settings -> Git.
3. Have an `api/` directory at the root of your project.

Your API will be automatically deployed for every push to the `master` or the `main` branch of your repository.

## Example code

```js:api/index.js
module.exports = (req, res) => {
  const { name = 'World' } = req.query;
  res.status(200).send(`Hello ${name}!`);
};
```

## Paths

The folder structure inside the `api/` folder will resolve the endpoints.

> If you're deploying your frontend to [Vercel](https://vercel.com) you can add `api` to `.vercelignore` so the API-folder does not conflict with Vercel's deployment.

### Example paths and endpoints

Given this folder and file structure:

```bash
|____api
| |____index.js
| |____users
| | |____index.js
| | |____active.js
| |____my-company.js
```

The following endpoints will be available:

```bash
https://api-str.nhost.app/ - (api/index.js)
https://api-str.nhost.app/users - (api/users/index.js)
https://api-str.nhost.app/users/active - (api/users/active.js)
https://api-str.nhost.app/my-company - (api/my-company.js)
```

## Environment variables

System level environment variables are available:

```bash
NHOST_HASURA_URL - (Hasura URL)
NHOST_HASURA_ADMIN_SECRET - (Hasura admin secret)
NHOST_HBP_URL - (HBP URL for auth and storage)
NHOST_CUSTOM_API_URL - (Custom API URL)
NHOST_WEBHOOK_SECRET - (Random secret string. Can be used to authenticate requests from Hasura to the Custom API)
```

You can access each environment variable via `process.env.<name>` ex: `process.env.NHOST_HASURA_URL`.

All your production environment variables added under Settings -> Environment variables are also added to the custom API.

For local development all system environment variables will point to the local development URLs.

## Logs

Logs are not available yet.

## Local development

Use the [Nhost CLI's `nhost dev`](/cli/dev) to start the Custom API locally (together with a full Nhost backend).

## TypeScript support

TypeScript is supported.

```js:api/index.ts
import { Request, Response } from "express";

export default (req: Request, res: Response) => {
  const { name = 'World' } = req.query;
  res.status(200).send(`Hello ${name}!`);
};
```

## Technical details

We use [Google Cloud Run](https://cloud.google.com/run) to deploy the Custom API. For now we only allow JavaScript. In the future you will be able to bring your own Dockerfile with any language.

---

## File: src/pages/graphql/index.mdx

---
title: "GraphQL"
---

GraphQL is a query language for APIs, which provides a complete and understandable description of the data in your API, gives you the power to ask for exactly what you need.

The GraphQL schema is automatically generated from your tables, which means **zero configuration**!

GraphQL was first developed by Facebook in 2012 and has since then been widely adopted by companies such as Github, Twitter, Medium, PayPal and others.

[GraphQL.org](http://graphql.org/)

---

## File: src/pages/graphql/mutation.mdx

---
title: "GraphQL Mutation"
---

GraphQL mutations are used to either **insert**, **update**, **upsert**, or **delete** data.

## Insert

The simplest type of mutation is an insert.

```graphql:Mutation
mutation InsertTodo {
  insert_todos(
    objects: [
      {
        title: "Delete Firebase account"
        body: "Migrate to nhost.io"
        done: false
      }
    ]
  ) {
    returning {
      id
      title
      body
      done
    }
  }
}
```

```json:Response
{
  "data": {
    "insert_todos": [
      {
        "id": "bf4b01ec-8eb6-451b-afac-81f5058ce852",
        "title": "Delete Firebase account",
        "body": "Migrate to nhost.io",
        "done": true
      }
    ]
  }
}
```

### Insert multiple rows

You can add multiple rows at once with an array as the `objects` property. This can be useful for migrating data.

```graphql:Mutation
mutation InsertMultipleTodos {
  insert_todos(
    objects: [
      {
        title: "Build the front end"
        body: "Mobile app or website first?"
        done: false
      }
      { title: "Launch 🚀", body: "That was easy", done: false }
    ]
  ) {
    returning {
      id
      title
      body
      done
    }
  }
}
```

## Update

You can update your data with a mutation. You can update multiple rows at once, for example marking all todos assigned to yourself as done.

> **Update mutations** are for when you know the data exists. Use an [upsert](/graphql/mutation#upsert) mutation if you want to optionally create or update data depending on whether it exists.

For example, to mark a todo as done, you would use an update mutation, based on the id of your table:

```graphql:Mutation
mutation UpdateTodoStatus($id: uuid, $done: Boolean) {
  update_todos(_set: { done: $done }, where: { id: { _eq: $id } }) {
    returning {
      body
      done
      title
    }
  }
}
```

Notice how we are using variables as the `id` and `done` properties, which lets us mark any todo as done or not done with the same mutation.

## Upsert

An **upsert** mutation will insert an object into the database in case there is no conflict with another row in the table. In case there is a conflict with one or more rows, it will either update the fields of the conflicted rows or ignore the request, depending on your mutation.

In order to convert your `insert` mutation to an upsert, you need to add an `on_conflict` property, which tells Hasura which fields it should use to find duplicates.

> The `on_conflict` key can only be a unique key in your database.

For an upsert, **all columns need to be passed**. This is different to an update mutation.

> Upsert mutations are for when you are not sure if the data already exists. Use an [update](/graphql/mutation#update) mutation if you know it does.

### Upsert example

We have set the title to a unique value, which means that you cannot have multiple todos with the same title. If you would like to overwrite the existing data, use a upsert mutation which is constrained to the title:

```graphql:Mutation
mutation UpsertTodo {
  insert_todos(
    objects: {
      title: "Delete Firebase account"
      body: "Migrate to an nhost.io project"
      done: false
    }
    on_conflict: { constraint: todos_title_key, update_columns: [body, done] }
  ) {
    returning {
      body
      done
      id
      title
    }
  }
}
```

This will update the `body` and `done` properties of the todo title to 'Delete Firebase account'.

### Conditional upsert

Insert a new object in the `article` table, or if the primary key constraint `todos_title_key` is violated, update the columns specified in `update_columns` only if the provided `where` condition is met.

For example, you may want to only update an existing todo if it is not done:

```graphql:Mutation
mutation UpsertTodo {
  insert_todos(
    objects: {
      title: "Delete Firebase account"
      body: "Migrate to an nhost.io project"
      done: false
    }
    on_conflict: {
      constraint: todos_title_key
      update_columns: [body, done]
      where: { done: { _eq: false } }
    }
  ) {
    returning {
      body
      done
      id
      title
    }
  }
}
```

### Ignore mutation on conflict

If `update_columns` is **empty** Hasura ignore the mutation if there is a conflict.

Insert a new object into the author table or, if the unique constraint `todos_title_key` is violated, ignore the request.

Here we have set the `title` to a unique key, to prevent multiple tasks with the same name. We want to avoid overwriting existing todos, so the update_columns array is empty:

```graphql:Mutation
mutation InsertTodo {
  insert_todos(
    objects: {
      title: "Delete Firebase account"
      body: "Migrate to nhost.io"
      done: false
    }
    on_conflict: { constraint: todos_title_key, update_columns: [] }
  ) {
    returning {
      body
      done
      id
      title
    }
  }
}
```

In this case, the insert mutation is ignored because there is a conflict and `update_columns` is empty.

## Delete

To delete your data, use a delete mutation.

This mutation will delete all `todos` where `done` is `true`:

```graphql:Mutation
mutation DeleteDoneTodos {
  delete_todos(where: { done: { _eq: true } }) {
    affected_rows
  }
}
```

If you have set up foreign keys which will restrict a delete violation, you will get an error and will not be able to delete the data until all violations are solved. The simplest way to solve this is by set **On Delete Violation to CASCADE** when you set up a Foreign Key.An

### Soft deletes

Sometimes it is better to keep data rather than deleting outright. In this case, you can add a boolean `deleted` property with a default value of `false` to your table. When a user deletes data, you set `deleted` to `true`.

Use a custom check in the permission settings to stop users from accessing deleted items.

---

## File: src/pages/graphql/query.mdx

---
title: "GraphQL Query"
---

You can **read data** with a GraphQL **query**. The best way to get started is with the Hasura console or with a GraphQL explorer, like GraphiQL.

Here is an GraphQL query that selects `title`, `body`, and `done` for every row in your `todos` table.

```graphql:Query
query GetTodos {
  todos {
    title
    body
    done
  }
}
```

```json:Response
{
  "data": {
    "todos": [
      {
        "title": "Delete Firebase account",
        "body": "Migrate to nhost.io",
        "done": false
      }
    ]
  }
}
```

GraphQL queries can be more complex, with filters, limits, sorting and aggregation.

This GraphQL query selects all items in the `todo` table that aren't `done`, with the total number of comments and the last five comments.

```graphql:Query
query GetTodosWithLatestComments {
  todos(where: { done: { _eq: false } }) {
    title
    body
    comments(limit: 5, order_by: { created_at: desc }) {
      comment
      created_at
      author
    }
    comments_aggregate {
      aggregate {
        count(columns: id)
      }
    }
  }
}
```

```json:Response
{
  "data": {
    "todos": [
      {
        "title": "Delete Firebase account",
        "body": "Migrate to nhost.io",
        "comments": [
          {
            "comment": "Let's do this",
            "created_at": "2019-10-31T08:34:25.621167+00:00",
            "author": "John"
          },
          {
            "comment": "🎉",
            "created_at": "2019-10-31T08:33:18.465623+00:00",
            "author": "Charlie"
          }
        ],
        "comments_aggregate": {
          "aggregate": {
            "count": 2
          }
        }
      }
    ]
  }
}
```

A great place to get started with setting up queries is in the Hasura Console.

---

## File: src/pages/graphql/subscription.mdx

---
title: "GraphQL Subscription"
---

Subscriptions are the same as queries, except they use WebSockets to keep the data up to date in your app. Subscriptions allow realtime updates!

Change `query` to `subscription` to create a subscription:

```graphql{1}
subscription GetTodos {
  todos {
    title
    body
    done
  }
}
```

That's it!

> Your data is always in sync when using subscriptions. It does not matter if the data changes through GraphQL or directly in the database. The data is always syncing in realtime using subscriptions.

---

## File: src/pages/graphql/variables.mdx

---
title: "GraphQL Variables"
---

You can send variables to your GraphQL queries and mutations. The variables and the type must be specified, ex: `$title: String!` or `$todo: todos_insert_input!`.

```graphql{1-2}:Mutation
mutation($todo: todos_insert_input!) {
  insert_todos(objects: [$todo]) {
    affected_rows
  }
}
```

> Because GraphQL is strongly typed you must specify the variable types.

Here is an example using variables with the popular Apollo client.

```js
import { gql, useMutation } from "@apollo/client";

const INSERT_TODO = gql`
  mutation($todo: todos_insert_input!) {
    insert_todos(objects: [$todo]) {
      affected_rows
    }
  }
`;

function Component() {
  //...
  const [insertTodo] = useMutation(INSERT_TODO);
  //...

  return (
    <form
      onSubmit={async (e) => {
        e.preventDefault();

        try {
          await insertTodo({
            variables: {
              todo: {
                name: todoName,
              },
            },
          });
        } catch (error) {
          console.error(error);
          return alert("Error creating todo");
        }
        alert("Todo created");
        setTodoName("");
      }}
    >
      //...
    </form>
  );
}
```

---

## File: src/pages/hasura/event-triggers.mdx

---
title: "Event triggers"
---

Hasura can trigger webhooks on events (insert, update, delete) happening in the database.

> The event in the database **does not have to** come via the GraphQL API.

As an example, let's imagine you are building a e-commerce system and you want to send an email when for every new order. To achieve that, create an event trigger on `insert` for the `orders` table. Now for every new order Hasura will send a webhook with the order-information for all new orders.

In the webhook, you get all order information and can send an email to the customer.

## API

You can use any other hosting service to host your API that will receive webhooks from Hasura's event triggers. We recommend [Netlify](http://netlify.com/) or [Vercel](https://vercel.com/) because they are easy to get started with.

## Security

To make sure that the request your API receives comes from your Hasura instance, and not a hacker, you can use the `NHOST_WEBHOOK_SECRET` environment variable that is already added to both Hasura and the [Custom API](/custom-api).

Set a header `x-webhook-secret` and use the `NHOST_WEBHOOK_SECRET` environment variable.



In your API, when you receive the webhook, you can control that the header (`x-webhook-secret`) to make sure the request is legit.

```js
if (req.headers["x-webhook-secret"] !== process.env.NHOST_WEBHOOK_SECRET) {
  return send(res, 401, "incorrect webhook secret");
}
// continue with your webhook
```

---

## File: src/pages/hasura/index.mdx

---
title: "Hasura"
---

Every Nhost project comes with a [Hasura](https://hasura.io). Hasura comes with the GraphQL Engine, Hasura console, event triggers, remote schemas and more.

## GraphQL Engine

Hasura automatically generates a GraphQL API based on your PostgreSQL database. This GraphQL handles

- queries (read data).
- mutations (insert, update, delete data).
- subscriptions (read data in realtime).

## Hasura Console

In the Hasura console you can manage tables, relations, data, permissions, events and remote schemas.

## Event triggers

Send HTTP webhooks based on events (insert, update, delete) in the database.

## Remote Schemas

Stitch together a remote GraphQL with the GraphQL API.

---

## File: src/pages/hasura/permissions.mdx

---
title: "Permissions"
---

The GraphQL API is protected by a permission system using roles. The permission system is based on [JWT tokens](https://jwt.io/introduction/). The user gets a JWT token upon login. This JWT token is being sent as a header with all GraphQL API requests to authenticate the user so correct permissions can be applied.

The JWT-token contains specific user information, such as user id. In the permission system in Hasura you can specify what a user is allowed to do based on ex the user id in the JWT-token and the data.

**A common use-case** is to allow a user read _something_ if `user_id` in the database is equal to the user id (`x-hasura-user-id`) in the JWT token.

By default, every user has the following session variables that can be used when creating permission rules:

```bash
x-hasura-user-id
x-hasura-allowed-roles
x-hasura-default-role
```

> The default role for a user is `user`.

You can add more session variables (like `users.company_id`) manually with [custom user columns](/auth/custom-user-columns).

You handle permissions for a table in the **Permissions tab**.

### Insert permission

Here is a popular approach for insert permission for logged in users. We'll break it down below the image.



1. Use the role **user** and click on the **Insert** column.
2. Select **Without any checks**.
3. Select the columns you want the user to insert. Here we'll only select `name` since the other columns will be filled in with default values and we don't want users to override them.
4. For column presets we select `user_id` to be the value of `x-hasura-user-id` (the user's id). This way, we make sure that the `user_id` is securely set to the id of the user making the request.

### Select permission

Below follows a popular approach for select permission for logged in users. We'll break it down below the image.



1. Use the role **user** and click on the **Select** column.
2. Select **With custom check** and create the rule that users can only read rows where `user_id = x-hasura-user-id`. In other words, users can only read their own data.
3. Limit number of rows to 100 (or some other relevant number).
4. Select the columns you want the user to be able to read. In our case we'll allow the user to read all columns.

### Update and Delete permission

Update and Delete permissions usually follows the same rules as Select permissions.

---

## File: src/pages/hasura/remote-schemas.mdx

---
title: "Remote schemas"
---

With Hasura remote schemas, you can add any external GraphQL API to your GraphQL API.

You can test this by adding this [Pokémon](https://xkcd.com/178/) GraphQL API: `https://graphql-pokemon.now.sh`.

Now you can query Pokémons in your API:

```graphql
query {
  pokemons(first: 3) {
    id
    name
    image
    attacks {
      fast {
        damage
        name
        type
      }
      special {
        damage
        name
        type
      }
    }
  }
}
```

---

## File: src/pages/hasura/tables.mdx

---
title: "Tables"
---

You can manage your PostgreSQL database tables directly in the Hasura console.

## Create table

Creating a table in the Hasura Console (recommended) does two things:

1. Creates the table in PostgreSQL.
2. Hasura tracks the table and automatically generates a GraphQL API.

> You can also [create tables directly in PostgreSQL](/postgresql/create-tables-in-postgresql).

### How to create a table

1. In the **Hasura Console**. Click on the **Add table** in the left menu.
2. Choose a **Table name**.
3. Add your **Columns**.
4. Add a **Primary Key**. Usually this is your `id` column.
5. (Optional) Add Foreign Keys if any.
6. (Optional) Add Unique Keys.
7. (Optional) Add a comment.
8. Click **Add table**.

### Frequently used columns

Frequently used columns are a quick way to add frequently used columns.



#### id (integer)

Creates a column called `id` with an `Integer` type. The column automatically increments for every row.

Example values: `1,2,3`.

**Why use Integers?**

Integers can be sorted based on when the row was created. They are also easier to remember and debug.

---

#### id (bigint)

Same as id (integer) but can hold larger values.

---

#### id (UUID)

Creates a column called `id` with an `UUID` type. The column automatically generates a new UUID for every row.

Example value: `cc3d4bc2-39a8-4efc-9ef0-c71b899d113a`

**Why use UUID?**

UUIDs does not leak information about the number of rows in your database. Using a UUID also means that one ID is unique across all databases in the world.

---

##### created_at

Automatically sets the row to the date of creation. **The value will stay the same if a row is updated**. The date is a timestamp with timezone data.

Example value: `2019-09-23T15:07:09.548632+00:00`

---

##### updated_at

Automatically sets the row to the date of creation. **This will update to the current date every time a row is updated**. The date is a timestamp with timezone data.

Example value: `2019-09-23T15:07:09.548632+00:00`

---

## Modify table

1. Click on the **table** you want to edit in the left menu.
2. Click on **Modify**.
3. Modify the table column.

## Delete table

1. Click on the **table** you want to delete in the left menu.
2. Click on **Modify**.
3. Scroll to the bottom and click on **Delete table**.
4. Type the **name of the table** you want to delete and **click OK** to confirm deletion.

> The table you want to delete might have existing relationships tracked by Hasura. When you try to delete such a table you will be asked to extra confirmation to delete those relationships too.

## Track tables

If you create tables directly into PostgreSQL (not via the Hasura console) you must track those tables in the Hasura console. When you track a table the GraphQL API gets updated automatically to include the fields.

1. Click on **Data** in the top menu.
2. A list of untracked tables is presented.
3. Click **Track All** (recommended) or click **Track** for each table you want to track.

## Track foreign-key relations

1. Click on **Data** in the top menu.
2. A list of untracked foreign-key relations is presented.
3. Click **Track All** (recommended) or click **Track** for each relationship you want to track.

---

## File: src/pages/libraries/nhost-js-sdk.mdx

---
title: "Nhost JS SDK"
---

> JavaScript SDK for handling **Auth** and **Storage**

## Installation

```bash
$ npm install nhost-js-sdk
```

or

```bash
$ yarn add nhost-js-sdk
```

## Setup

```js:/src/utils/nhost
import { createClient } from "nhost-js-sdk";

const nhostClient = createClient({
  baseURL: "https://backend-url.nhost.app",
})

const auth = nhostClient.auth;
const storage = nhostClient.storage;

export { auth, storage };
```


| Parameters                 |               |          |                                                                                         |   |
|----------------------------|---------------|----------|-----------------------------------------------------------------------------------------|---|
| *baseURL*                  | string        | required | Backend URL                                                                             |   |
| *useCookies*               | boolean       | optional | Use cookies for auth (defaults to `false`)                                              |   |
| *refreshIntervalTime*      | number        | optional | Autorefresh interval in ms (defaults to `Math.max(30 * 1000, JWTExpiresIn - 45000)`)    |   |
| *ssr*                      | boolean       | optional | Enable server-side rendering mode (defaults to `typeof window === "undefined"`)         |   |
| *autoLogin*                | boolean       | optional | Auto logins user (defaults to `true`)                                                   |   |
| *clientStorage*            | ClientStorage | optional | Storage to use (defaults to `window.localStorage`)                                      |   |
| *clientStorageType*        | string        | optional | Storage type (defaults to `web`)                                                        |   |


## Usage

```js
import { auth, storage } from "src/utils/nhost";
```

### Auth

Creating a user with email and password is done with `register()`. For OAuth, the `login()` function creates the user on the first login attempt.

```js
auth.register({ email, password });

// with options
auth.register({
  email,
  password,
  options: { userData: { display_name: "Joe Doe" } },
});
```

Existing users can login with email and password or using an OAuth provider.

```js
auth.login({ email, password });

// OAuth provider: google | github | linkedin ...
auth.login({ provider })
```

Users can logout via `logout()`.

```js
auth.logout();
```

To register a callback to run when the auth state changes (e.g., when a user logs out) is done via `onAuthStateChanged()`.

```js
auth.onAuthStateChanged((loggedIn) => {
  console.log("auth state changed!");
  console.log({ loggedIn });
});
```

To check if a user is logged in or not use `isAuthenticated()`.

```js
auth.isAuthenticated();
```

### notes:
- `true` means the user is logged in
- `false` means the user is not logged in
- `null` means that a request to login the user is ongoing.

For getting a user session's JWT Token use `getJWTToken()`.

```js
auth.getJWTToken();
```

And for its claims `getClaim()`.

```js
auth.getClaim("x-hasura-user-id");
```

To activate a user account use `activate()`.

```js
auth.activate(<ticket>);
```

For changing an account's email address without confirmation use `changeEmail()`. The user must be logged in.

```js
auth.changeEmail(new_email);
```

Or with a confirmation email `requestEmailChange()`.

```js
auth.requestEmailChange(new_email);
```

To confirm the email change use `confirmEmailChange()` and pass in the `ticket` received with the email.

```js
auth.confirmEmailChange(ticket);
```

For changing a user's password use `changePassword()`.

```js
auth.changePassword(oldPassword, newPassword);
```

Or with a confirmation email use `requestPasswordChange()`.

```js
auth.requestPasswordChange(email);
```

To confirm the password change use `confirmPasswordChange()`.

```js
auth.confirmPasswordChange(new_password, ticket);
```

To generate a MFA QR-code use `MFAGenerate()`. The user must be logged in.

```js
auth.MFAGenerate();
```

Enabling MFA is done via `enable()`.

```js
auth.enable(code);
```

And disabling is done via `disable()`.

```js
auth.disable(code);
```

To login using MFA TOTP use `MFATotp()` and pass in the `ticket` returned by `login()` (when MFA is enabled).

```js
auth.MFATotp(code, ticket);
```

### Storage

Uploading a file is done using `put()`.

```js
storage.put(path, file, metadata?, onUploadProgress?);
```

To delete a file use `delete()`.

```js
storage.delete(path);
```

To get the metadata for a file use `getMetadata()`.

```js
storage.getMetadata(path);
```

### Other environments

#### React Native

Install:

```bash
$ yarn add @react-native-community/async-storage
```

Installation instructions can be found at [https://react-native-community.github.io/async-storage/docs/install](https://react-native-community.github.io/async-storage/docs/install).

```js
import createClient from "nhost-js-sdk";
import AsyncStorage from "@react-native-async-storage/async-storage";

const nhostClient = createClient({
  baseURL: "https://backend-url.nhost.app",
  clientStorage: AsyncStorage,
  clientStorageType: "react-native",
});

const { auth, storage } = nhostClient;

export { auth, storage };
```

#### Ionic

```js
import createClient from "nhost-js-sdk";
import { Plugins } from "@capacitor/core";
const { Storage } = Plugins;

const nhostClient = createClient({
  baseURL: "https://backend-url.nhost.app",
  clientStorage: Storage,
  clientStorageType: "capacitor
})

const auth = nhostClient.auth;
const storage = nhostClient.storage;

export { auth, storage };
```

#### Expo

Install:

```bash
$ expo install expo-secure-store
```

More info: [https://docs.expo.io/versions/latest/sdk/securestore/](https://docs.expo.io/versions/latest/sdk/securestore/).

```js
import createClient from "nhost-js-sdk";
import * as SecureStore from "expo-secure-store";

const nhostClient = createClient({
  baseURL: "https://backend-url.nhost.app",
  clientStorage: SecureStore,
  clientStorageType: "expo-secure-storage",
})

const auth = nhostClient.auth;
const storage = nhostClient.storage;

export { auth, storage };
```

---

## File: src/pages/libraries/nhost-nuxt.mdx

---
title: "@nhost/nuxt"
---

[NuxtJS](https://nuxtjs.org/) module to use Nhost's GraphQL, authentication and storage in a NuxtJS app.

## Installation

Using NPM:

```bash
$ npm install --save @nhost/nuxt
```

or using Yarn:

```bash
$ yarn add @nhost/nuxt
```

> Other recommended NPM packages: `nhost-js-sdk @nuxtjs/apollo graphql-tag`

Add the module and configure nhost in `nuxt.config.js`:

```js
{
  modules: [
    '@nhost/nuxt'
  ],
  nhost: {
    baseURL: "https://backend-REPLACE.nhost.app"
    // optional other nhost-js-sdk setup options
  }
}
```

Check out our [documentation](/libraries/nhost-js-sdk#setup) for all the available `nhost-js-sdk` options.

## Middleware

This module provides a middleware that automatically handles auth guards to protect pages.

1. Add `nhost/auth` to your Nuxt config middleware:

```js
{
  router: {
    middleware: ["nhost/auth"];
  }
}
```

2. Define the `home` and `logout` routes on the nhost config

```js
{
  nhost: {
    routes: {
      home: '/dashboard',
      logout: '/'
    }
  }
}
```

Users who attempt to access auth guarded pages without being logged in gets redirected to the `logout` route, and users who are logged in and attempt to access guest pages gets redirected to the `home` route.

These routes can also be set to either `undefined` or `false` which will disable their respective functionality. They are also available under `this.$nhost.$options.routes` on Vue components or `ctx.$nhost.$options.routes` on the Nuxt Context.

3. Finally, add an `nhostAuth` property to your Nuxt pages:

```js
export default {
  nhostAuth: true,
};
```

`nhostAuth` takes the following values:

1. `true`: Users must be authenticated to access this page. If the user is not authenticated, the user gets redirected to the `logout` route.
2. `false`: This is the default value; no authentication required.
3. `'guest'`: This page can only be accessed by unauthenticated users. Users who are logged in will be redirected to the `home` route.

## Typescript

If you're using Typescript, make sure to include `@nhost/nuxt` to your Typescript config types:

```js
{
  compilerOptions: {
    types: ["@nhost/nuxt"];
  }
}
```

## Nuxt-apollo (@nuxtjs/apollo)

To use this library with `@nuxtjs/apollo`, create two Nuxt plugins: `nuxt-apollo-config.js` and `nhost-apollo-ws-client.js` inside your `plugins` folder with the following content:

---

```js:plugins/nuxt-apollo-config.js
export default (ctx) => {
  return {
    httpEndpoint: "https://hasura-<REPLACE>.nhost.app/v1/graphql",
    wsEndpoint: "wss://hasura-<REPLACE>.nhost.app/v1/graphql",
    getAuth: () => {
      const token = ctx.$nhost.auth.getJWTToken();
      return token ? `Bearer ${token}` : null;
    },
  };
};
```

```js:nhost-apollo-ws-client.js
export default (ctx) => {
  const subscriptionClient = ctx.app.apolloProvider.defaultClient.wsClient;

  ctx.$nhost.auth.onAuthStateChanged((state) => {
    if (subscriptionClient.status === 1) {
      subscriptionClient.close();
      subscriptionClient.tryReconnect();
    }
  });

  ctx.$nhost.auth.onTokenChanged(() => {
    if (subscriptionClient.status === 1) {
      subscriptionClient.tryReconnect();
    }
  });
};
```

Then, in your Nuxt config:

```json:nuxt.config.js
{
  [...]
  "plugins": [
    {
      "src": "~/plugins/nhost-apollo-ws-client.js",
      "mode": "client"
    }
  ],
  "apollo": {
    "clientConfigs": {
      "default": "~/plugins/nhost-apollo-config.js"
    }
  },
  [...]
}
```

## Usage

This module exposes an `$nhost` property on the `Vue` object and on the NuxtJS `Context`, which is an instance of `NhostClient`.

## Example

You can find a full example project with this library and `@nuxtjs/apollo` [here](https://github.com/nhost/nhost/tree/main/examples/nuxt-apollo).

---

## File: src/pages/libraries/react-apollo.mdx

---
title: "@nhost/react-apollo"
---

Make it easy to use Apollo and React with your Nhost project.

`@nhost/react-apollo` exposes one component: `NhostApolloProvider`. Wrap your whole App around this component to make GraphQL requests anywhere from your app.

It's recommended to use `@nhost/react-apollo` with [`@nhost/react-auth`](/libraries/react-auth) and [`nhost-js-sdk`](/libraries/nhost-js-sdk) for users to login and interact with the GraphQL API.

If you use `@nhost/react-apollo` and `NhostApolloProvider` **without** authentication (`auth` property) all GraphQL requests will be made with the `public` role.

## Install

```bash
npm install @nhost/react-apollo@v1.1.3 @nhost/react-auth@v1.0.5 nhost-js-sdk @apollo/client graphql
```

`@apollo/client` is required for `@nhost/react-apollo` to work and will be used to import `useQuery`, `useMutation`, and `useSubscription`.

### Initialize the Nhost client

```js:src/utils/nhost.js
import { createClient } from "nhost-js-sdk";

const config = {
  baseURL: "https://backend-REPLACE.nhost.app",
};

const { auth, storage } = createClient(config);

export { auth, storage };
```

Read more about [`nhost-js-sdk` here](/libraries/nhost-js-sdk).

## Create React App

See full [Nhost Create React App with Apollo](https://github.com/nhost/examples/tree/main/create-react-app-apollo).

```jsx:src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { NhostAuthProvider } from '@nhost/react-auth";
import { NhostApolloProvider } from "@nhost/react-apollo";
import { auth } from "utils/nhost";
import App from "./App";

ReactDOM.render(
  <React.StrictMode>
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint={`https://hasura-REPLACE.nhost.app/v1/graphql`}
      >
        <App />
      </NhostApolloProvider>
    </NhostAuthProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

## Next.js

See full [Nhost Next.js with Apollo](https://github.com/nhost/examples/tree/main/nextjs-apollo).

```jsx:pages/_app.js
import { NhostAuthProvider } from "@nhost/react-auth";
import { NhostApolloProvider } from "@nhost/react-apollo";

import { auth } from "utils/nhost";

function MyApp({ Component, pageProps }) {
  return (
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint={`https://hasura-REPLACE.nhost.app/v1/graphql`}
      >
        <Component {...pageProps} />
      </NhostApolloProvider>
    </NhostAuthProvider>
  );
}

export default MyApp;
```

Learn more about `auth` and `storage` in the [nhost-js-sdk library](/libraries/nhost-js-sdk).

## Usage

Since the `NhostApolloProvider` is now installed it's possible to use the Apollo client with its `useQuery`, `useSubscription`, and `useMutation` functions anywhere in your app.

```jsx
import { useQuery, gql } from "@apollo/client";

const GET_TODOS = gql`
  query {
    todos {
      id
      created_at
      name
      completed
    }
  }
`;

export function App() {
  const { loading, data } = useQuery(GET_TODOS);

  if (loading) {
    return <div>Loading..</div>;
  }

  return (
    <div>
      <h1>in app</h1>
      {!data ? (
        "no data"
      ) : (
        <ul>
          {data.todos.map((todo) => {
            return <li key={todo.id}>{todo.name}</li>;
          })}
        </ul>
      )}
    </div>
  );
}
```

## Options

Options and parameters for `NhostApolloProvider`.

| Parameter           | Description                                                                                                                                                              | Required |
| ------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: |
| `auth`              | The `auth` object from the Nhost Client                                                                                                                                  |   Yes    |
| `gqlEndpoint`       | GraphQL API Endpoint                                                                                                                                                     |   Yes    |
| `headers`           | Custom headers.                                                                                                                                                          |    No    |
| `publicRole`        | Public role that Apollo will automatically use if the user is not logged in. Will default to `public`.                                                                   |    No    |
| `cache`             | Customized cache. [More info](https://www.apollographql.com/docs/react/caching/cache-configuration/).                                                                    |    No    |
| `connectToDevTools` | Enable Apollo Dev tools. [More info](https://www.apollographql.com/docs/react/development-testing/developer-tooling/)                                                    |    No    |
| `onError`           | Custom function for error handling with Apollo link. [More info](https://www.apollographql.com/docs/react/data/error-handling/#advanced-error-handling-with-apollo-link) |    No    |

---

## File: src/pages/libraries/react-auth.mdx

---
title: "@nhost/react-auth"
---

Make it easy to use Authentication with your Nhost project.

`@nhost/react-auth` exposes one component: `NhostAuthProvider`. Wrap your whole App around this component to manage if users are logged in or not.

It's recommended to use `@nhost/react-auth` with [`@nhost/react-apollo`](/libraries/react-apollo) and [`nhost-js-sdk`](/libraries/nhost-js-sdk) for users to login and interact with the GraphQL API.

## Install

```bash
npm install @nhost/react-auth@v1.0.5
```

## Create React App

### Setup

See full [Nhost Create React App with Apollo](https://github.com/nhost-examples/create-react-app-apollo).

```jsx:src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { NhostAuthProvider } from "@nhost/react-auth";
import { NhostApolloProvider } from "@nhost/react-apollo";
import { auth } from "utils/nhost";
import App from "./App";

ReactDOM.render(
  <React.StrictMode>
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint={`https://hasura-REPLACE.nhost.app/v1/graphql`}
      >
        <App />
      </NhostApolloProvider>
    </NhostAuthProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

### Usage

First, we'll create an `AuthGate` component. Only logged-in users are allowed through this component.

```jsx:src/components/auth-gate.js
import React from "react";
import { Redirect } from "react-router-dom";
import { useAuth } from "@nhost/react-auth";

export function AuthGate({ children }) {
  const { signedIn } = useAuth();

  if (signedIn === null) {
    return <div>Loading...</div>;
  }

  if (!signedIn) {
    return <Redirect to="/login" />;
  }

  // user is logged-in
  return children;
}
```

We'll wrap routes that we want to protect for logged-in users only using this component. In the example below, only logged-in users are allowed to access the `/`-route.

```jsx{7,19,23}:src/index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { NhostAuthProvider } from '@nhost/react-auth";
import { NhostApolloProvider } from "@nhost/react-apollo";
import { auth } from "utils/nhost";
import { AuthGate } from "components/auth-gate"
import App from "./App";

ReactDOM.render(
  <React.StrictMode>
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint={`https://hasura-REPLACE.nhost.app/v1/graphql`}
      >
        <Router>
          <Switch>
            <Route exact path="/login">
              <Login />
            </Route>
            <AuthGate>
              <Route exact path="/">
                <App />
              </Route>
            </AuthGate>
          </Switch>
        </Router>
      </NhostApolloProvider>
    </NhostAuthProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

## Next.js

See full [Nhost Next.js with Apollo](https://github.com/nhost/nhost/tree/main/examples/nextjs-apollo).

### Setup

```jsx:pages/_app.js
import { NhostAuthProvider } from "@nhost/react-auth";
import { NhostApolloProvider } from "@nhost/react-apollo";

import { auth } from "utils/nhost";

function MyApp({ Component, pageProps }) {
  return (
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint={`https://hasura-REPLACE.nhost.app/v1/graphql`}
      >
        <Component {...pageProps} />
      </NhostApolloProvider>
    </NhostAuthProvider>
  );
}

export default MyApp;
```

### Usage

First we'll create a `PrivateRoute` component. We'll wrap pages that only logged in users are allowed to access.

```jsx:components/private-route.jsx
import { useAuth } from "@nhost/react-auth";

export function PrivateRoute(Component) {
  return () => {
    const { signedIn } = useAuth();

    // wait to see if the user is logged in or not.
    if (signedIn === null) {
      return <div>Checking auth...</div>;
    }

    if (!signedIn) {
      return <div>Login form or redirect to `/login`.</div>;
    }

    return (<Component {...arguments} />);
  };
}
```

#### Usage

```jsx:pages/index.js
import { PrivateRoute } from "components/private-route";

function Home() {
  return <div>My dashboard</div>;
}

export default PrivateRoute(Dashboard);
```

---

## File: src/pages/postgresql/index.mdx

---
title: "PostgreSQL"
---

PostgreSQL is the world's most advanced open source database and every Nhost project has its own Postgres database.

## Version

The following versions of PostgreSQL is supported when creating a Nhost project:

- 12.0
- 11.5
- 10.5
- 9.6

## Prepared tables

Each newly created project's database have the following prepared tables:

- `public.users`
- `auth.account_providers`
- `auth.account_roles`
- `auth.accounts`
- `auth.providers`
- `auth.refresh_tokens`
- `auth.roles`

## Direct Access

> Every Postgres instance comes pre-configured with an SSL certificate

The PostgreSQL database can be accessed directly with a Postgres client such as pgAdmin, DBeaver, or Table Plus. Find the Postgres connection string in the Nhost console in the Postgres tab.

---

## File: src/pages/quick-start/authentication.mdx

---
title: "Authentication"
---

Currently, everyone can select and insert todos. That is ok to start with but now it's time to secure our API by adding authentication.

Authentication is built-in to Nhost and easy to get started.

## Create User

Let's first create our user by going to the project's **Auth** section.



You will use this user to access your todos later on. But first, we will install [nhost-js-sdk](/libraries/nhost-js-sdk) to help us with authentication.

## Install and Configure nhost-js-sdk

> `nhost-js-sdk` is an open-source JavaScript library for interacting with Nhost's auth and storage.

```bash
$ npm install nhost-js-sdk
```

Now, we need to configure and initialize a connection to Nhost. Create a new folder, `src/utils`, and create `nhost.js` inside it.

```js:src/utils/nhost.js
import { createClient } from "nhost-js-sdk";

const config = {
  baseURL: "https://backend-REPLACE.nhost.app",
};

const { auth, storage } = createClient(config);

export { auth, storage };
```

Please don't forget to replace `https://backend-REPLACE.nhost.app` with your endpoint.

## Add NhostAuthProvider

Now it's time to wrap our `App` with another provider. The `NhostAuthProvider`. This provider indicates if a user is logged in or not in the `AuthGate` component that we'll implement soon.

First let's install the `@nhost/react-auth` package:

```bash
$ npm install @nhost/react-auth@v1.0.5
```

We'll also pass our `auth` object as a prop to both providers, `NhostAuthProvider` and `NhostApolloProvider`, so that the whole app can share the same auth state.

```jsx{5,6,10,11,13,14}:src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { NhostApolloProvider } from "@nhost/react-apollo";
import { NhostAuthProvider } from "@nhost/react-auth";
import { auth } from "utils/nhost";

ReactDOM.render(
  <React.StrictMode>
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint="https://hasura-REPLACE.nhost.app/v1/graphql"
      >
        <App />
      </NhostApolloProvider>
    </NhostAuthProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

Now it's a good time to recap what has been done so far in this chapter. We started by creating a new user for our Nhost project, followed by installing and configuring `nhost-js-sdk`. Finally we wrapped our app with `NhostAuthProvider`, passing `auth` as a prop so that the same auth object gets used in both Nhost providers.

Now, let's create the login component.

## Login

We need to write a login component that handles the form's submission of a user's data and some scaffolding for the app routes.

Create a directory `src/components` and create the `Login` component with the following content:

```jsx:src/components/login.js
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { auth } from "utils/nhost";

export function Login(props) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const history = useHistory();

  async function handleSubmit(e) {
    e.preventDefault();

    // login
    try {
      await auth.login({email, password});
    } catch (error) {
      alert("error logging in");
      console.error(error);
      return;
    }

    // redirect back to `/`
    history.push("/");
  }

  return (
    <div>
      <h1>Login</h1>
      <form onSubmit={handleSubmit}>
        <input
          type="email"
          placeholder="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
        <input
          type="password"
          placeholder="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
        />
        <button>Login</button>
      </form>
    </div>
  );
}
```

Now let's create two routes. One for `/` where we'll have our todos listed, and one for `/login` where users can log in.

```jsx{4,5,14-19,21-23}:src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Login } from "components/login";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { NhostApolloProvider } from "@nhost/react-apollo";
import { NhostAuthProvider } from "@nhost/react-auth";
import { auth } from "utils/nhost";

ReactDOM.render(
  <React.StrictMode>
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint="https://hasura-REPLACE.nhost.app/v1/graphql"
      >
        <Router>
          <Switch>
            <Route exact path="/login">
              <Login />
            </Route>
            <Route exact path="/">
              <App />
            </Route>
          </Switch>
        </Router>
      </NhostApolloProvider>
    </NhostAuthProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

Finally, add two links to `App.js`. One to `/login` and one that will logout the user.

```jsx{3,4,21,22}:src/App.js
import React, { useState } from "react";
import { gql, useSubscription, useMutation } from "@apollo/client";
import { Link } from "react-router-dom";
import { auth } from "utils/nhost";

const GET_TODOS = gql`
  subscription {
    todos {
      id
      created_at
      name
      completed
    }
  }
`;

const INSERT_TODO = gql`
  mutation($todo: todos_insert_input!) {
    insert_todos(objects: [$todo]) {
      affected_rows
    }
  }
`;

function App() {
  const { data, loading } = useSubscription(GET_TODOS);
  const [insertTodo] = useMutation(INSERT_TODO);
  const [todoName, setTodoName] = useState("");

  if (loading) {
    return <div>Loading</div>;
  }

  return (
    <div>
      <Link to="/login">Login</Link>
      <div onClick={() => auth.logout()}>Logout</div>
      <div>
        <form
          onSubmit={async (e) => {

          [...]

        </form>
      </div>
      {!data ? (
        "no data"
      ) : (
        <ul>
          {data.todos.map((todo) => {
            return <li key={todo.id}>{todo.name}</li>;
          })}
        </ul>
      )}
    </div>
  );
}

export default App;
```

Phew, that's a lot of code. Let's stop here and recap what we have.

Both routes (`/` and `/login`) are still unprotected. We'll fix that soon. When we visit `/` we still see all todos. That's fine for now since we allow the `public` role to select them.

On the other hand, when we log in, we see **No data**. And if we log out again, our todos are back. What's going on?

When logged out, the `public` role was used, which still had permissions to select todos. When we log in, the `user` role was used instead, which doesn't have permission to select todos. Yet!

Things we need to do to secure our app:

- Protect the `/` route so that it is available to **logged-in** users only.
- Remove all permissions for the `public` role. Only **logged-in** users can insert and select todos.
- Add `user_id` to the `todos` table so that every todo belongs to a user.
- Set permissions so that users are only allowed to insert and select their todos.

## Auth Gate

Let's now create the `AuthGate` component that ensures only authenticated users can access specific routes.

```jsx:src/components/auth-gate.js
import { Redirect } from "react-router-dom";
import { useAuth } from "@nhost/react-auth";

export function AuthGate({ children }) {
  const { signedIn } = useAuth();

  if (signedIn === null) {
    return <div>Loading...</div>;
  }

  if (!signedIn) {
    return <Redirect to="/login" />;
  }

  return children;
}
```

`AuthGate` checks whether a user is logged in and redirects to `/login` otherwise.

In `src/index.js` we add the `AuthGate` component around the routes we want only logged-in users to access.

```jsx{5,20,24}:src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Login } from "components/login";
import { AuthGate } from "components/auth-gate";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { NhostApolloProvider } from "@nhost/react-apollo";
import { NhostAuthProvider } from "@nhost/react-auth";
import { auth } from "utils/nhost";

ReactDOM.render(
  <React.StrictMode>
    <NhostAuthProvider auth={auth}>
      <NhostApolloProvider
        auth={auth}
        gqlEndpoint="https://hasura-xxx.nhost.app/v1/graphql"
      >
        <Router>
          <Switch>
            <Route exact path="/login">
              <Login />
            </Route>
            <AuthGate>
              <Route exact path="/">
                <App />
              </Route>
            </AuthGate>
          </Switch>
        </Router>
      </NhostApolloProvider>
    </NhostAuthProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

Now users can only access `/` if they are logged-in.

## Connect todos to users

A todo should belong to a user and only be visible to that user. Before we do that **all existing todos must be deleted**. To delete all existing todos, click **Browse Rows** for the `todos` table, select all todos and click on the trash can icon.

That deleted all todos. Now let's add the new `user_id` column.

Click on **Modify** and then click the button **Add a new column**. Name the new column `user_id` with the type `UUID`. Make sure to **uncheck Nullable**. Click **Save**.

> `user_id` refers to the **id** of the **user** the todo belongs to.



For our GraphQL API and database to understand that the `user_id` refers to the user's id we need to create a **Foreign Key**.

> A Foreign key is a link between two tables

The foreign key links the `users` table to the `todos` table.

You create the foreign key in the same **Modify** tab. Scroll down a bit to **Foreign Keys** and click **Add**. See the image below of how to set the Foreign Key and click **Save**.



For Hasura to use the foreign key relation in the GraphQL API, we need to track the foreign key relationship. Go to the **DATA** tab and click **Track all**.



## Permissions for users

### Remove permissions for the public role

We won't use the `public` role anymore, so let's remove all permission for that role. See the image below.



Now we'll add permissions for the `user` role.

> All logged-in users have the `user` role.

### Insert

First, we'll set the **Insert permission**.

A user can only insert `name` because all other columns will be set automatically. More specifically, `user_id` will be set to the id of the user making the request (`x-hasura-user-id`) and is configured in the `Column presets` section. See the image below.



### Select

For **Select permission**, set a **custom check** so users can only select todos where `user_id` is the same as their user id. In other words: users are only allowed to select their own todos. See the image below.



# The app is completed

You have probably already tested your app during this guide, but you have finished you're app. Congratulations!

---

## File: src/pages/quick-start/deploy-app.mdx

---
title: "Deploy app"
---

Your app is ready to be deployed. You only need to deploy your frontend app since the backend is already deployed and production-ready at Nhost.

You can use your favorite platform to deploy your frontend app. We recommend using [Netlify](https://netlify.com) or [Vercel](https://vercel.com), or [Stormkit](https://www.stormkit.io) because they are performant and easy to use.

For a more complete list of hosting alternatives, check the [Create React App Deployment](https://create-react-app.dev/docs/deployment/).

---

## File: src/pages/quick-start/frontend-web-app.mdx

---
title: "Frontend Web App"
---

At this point, we have all the backend (database table, permissions, and an API) needed to store and retrieve todos from any frontend app. It is now time to start building the actual frontend app!

## React app

We are going to use [create-react-app](https://github.com/facebook/create-react-app) because it is the easiest way to get started, and it offers a modern build setup with no configuration.

Create a new react app:

```bash
$ npx create-react-app nhost-todos
```

Once completed, change the directory to the new project and install these packages. The packages will be used to send GraphQL requests to the Nhost backend.

```bash
$ cd nhost-todos
$ npm install @nhost/react-apollo@v1.1.3 @apollo/client graphql react-router-dom
```

Create a `jsconfig.json` file in the root of your project to make [imports easier](https://create-react-app.dev/docs/importing-a-component/#absolute-imports).

```json:jsconfig.json
{
  "compilerOptions": {
    "baseUrl": "src"
  },
  "include": ["src"]
}
```

Start the app.

```bash
$ npm start
```

## Add NhostApolloProvider to index.js

`NhostApolloProvider` comes from [@nhost/react-apollo](https://www.npmjs.com/package/@nhost/react-apollo) and deals with all the boilerplate for having `ApolloClient` configured to communicate securely with Nhost.

Import `NhostApolloProvider` and wrap `App` so that GraphQL is available everywhere in your app.

> Replace `https://hasura-xxx.nhost.app/v1/graphql` with your project's GraphQL API endpoint. You can find the endpoint in your project's dashboard.

```jsx{4,8,10}:src/index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { NhostApolloProvider } from "@nhost/react-apollo";

ReactDOM.render(
  <React.StrictMode>
    <NhostApolloProvider gqlEndpoint="https://hasura-xxx.nhost.app/v1/graphql">
      <App />
    </NhostApolloProvider>
  </React.StrictMode>,
  document.getElementById("root")
);
```

Now we can fetch data!

## Fetch data using GraphQL in App.js

Replace all content of `src/App.js` with the following code:

```jsx:src/App.js
import React from "react";
import { gql, useQuery } from "@apollo/client";

const GET_TODOS = gql`
  query {
    todos {
      id
      created_at
      name
      is_completed
    }
  }
`;

function App() {
  const { data, loading } = useQuery(GET_TODOS);

  if (loading) {
    return <div>Loading</div>;
  }

  return (
    <div>
      {!data ? (
        "No todos"
      ) : (
        <ul>
          {data.todos.map((todo) => {
            return <li key={todo.id}>{todo.name}</li>;
          })}
        </ul>
      )}
    </div>
  );
}

export default App;
```

Your two previous todos now appear in your app.

Let's move on and add functionality to insert new todos.

## Insert todos

We need to create a GraphQL mutation and add a simple form for inserting todos.

```jsx{1,2,6,19-43}:src/App.js
import React, { useState } from "react";
import { gql, useQuery, useMutation } from "@apollo/client";

const GET_TODOS = gql`
  query {
    todos {
      id
      created_at
      name
      is_completed
    }
  }
`;

const INSERT_TODO = gql`
  mutation($todo: todos_insert_input!) {
    insert_todos(objects: [$todo]) {
      affected_rows
    }
  }
`;

function App() {
  const { data, loading } = useQuery(GET_TODOS);
  const [insertTodo] = useMutation(INSERT_TODO);
  const [todoName, setTodoName] = useState("");

  if (loading) {
    return <div>Loading</div>;
  }

  return (
    <div>
      <div>
        <form
          onSubmit={async (e) => {
            e.preventDefault();

            try {
              await insertTodo({
                variables: {
                  todo: {
                    name: todoName,
                  },
                },
              });
            } catch (error) {
              console.error(error);
              return alert("Error creating todo");
            }
            alert("Todo created");
            setTodoName("");
          }}
        >
          <input
            type="text"
            placeholder="todo"
            value={todoName}
            onChange={(e) => setTodoName(e.target.value)}
          />
          <button>Create todo</button>
        </form>
      </div>
      {!data ? (
        "no data"
      ) : (
        <ul>
          {data.todos.map((todo) => {
            return <li key={todo.id}>{todo.name}</li>;
          })}
        </ul>
      )}
    </div>
  );
}

export default App;
```

Great! We can now insert new todos. But for the new todos to be listed, we have to reload the page ourselves. We can do better, so let's fix that by introducing subscriptions.

> Subscriptions updates data in realtime. When the data changes in the database, our app instantly updates and shows the newest data. It's almost like magic!

## Get data in realtime using subscriptions

We'll replace `useQuery` with `useSubscription` and `query` with `subscription` in `GET_TODOS`.

```jsx{2,4,9}:src/App.js
import React, { useState } from "react";
import { gql, useSubscription, useMutation } from "@apollo/client";

const GET_TODOS = gql`
  subscription {
    todos {
      id
      created_at
      name
      is_completed
    }
  }
`;

const INSERT_TODO = gql`
  mutation($todo: todos_insert_input!) {
    insert_todos(objects: [$todo]) {
      affected_rows
    }
  }
`;

function App() {
  const { data, loading } = useSubscription(GET_TODOS);
  const [insertTodo] = useMutation(INSERT_TODO);
  const [todoName, setTodoName] = useState("");

  if (loading) {
    return <div>Loading</div>;
  }

  return (
    <div>
      <div>
        <form
          onSubmit={async (e) => {
            e.preventDefault();

            try {
              await insertTodo({
                variables: {
                  todo: {
                    name: todoName,
                  },
                },
              });
            } catch (error) {
              alert("Error creating todo");
              console.error(error);
              return;
            }
            alert("Todo created");
            setTodoName("");
          }}
        >
          <input
            type="text"
            placeholder="todo"
            value={todoName}
            onChange={(e) => setTodoName(e.target.value)}
          />
          <button>Add todo</button>
        </form>
      </div>
      {!data ? (
        "no data"
      ) : (
        <ul>
          {data.todos.map((todo) => {
            return <li key={todo.id}>{todo.name}</li>;
          })}
        </ul>
      )}
    </div>
  );
}

export default App;
```

Perfect! New todos get listed in realtime when we create them. You can even open two tabs, add new todos in one tab and see how all windows display the latest data.

Your app has superpowers!

## Next

[Authentication](/quick-start/authentication)

---

## File: src/pages/quick-start/index.mdx

---
title: "Introduction"
---

import { YouTube } from "components/youtube";

<YouTube />

## Todo App

We are going to build a todo app using Nhost and React. We use React here, but Nhost is framework agnostic, so you can use whatever framework you like.
We will start by creating a backend on Nhost, followed by a React client application for managing todos. We will take an incremental approach to showcase Nhost's authentication system.

> As you follow this tutorial make sure to install the correct SDK dependencies for the current version of Nhost. Throughout this tutorial both `@nhost/react-apollo` and `@nhost/react-auth` are meant to be used on their version 1 (`@nhost/react-apollo@v1.1.3` and `@nhost/react-auth@v1.0.5` or lower releases) while version 2 of these packages are exclusive for the upcoming Nhost v2, now on private beta: [Nhost v2 Private Beta waitlist](https://waitlist.nhost.io/)

## Help

The quick start is simple enough that we expect you not to find any issues, but if you do, please reach out to us on [Discord](https://discord.gg/SZnpVck) or at support@nhost.io.

## Next step

[Nhost Backend](/quick-start/nhost-backend)

---

## File: src/pages/quick-start/nhost-backend.mdx

---
title: "Nhost Backend"
---

## Before we start:

- Please make sure you have [NodeJS](https://nodejs.org/en/) and [npm](https://www.npmjs.com/) installed.
- If you haven't already, please create an account on [Nhost](https://console.nhost.io/register).

## Create Project

We will create a project that will serve as the backend to our todo client application. Please log in to [Nhost](https://console.nhost.io), click on **Add new project**. Select a name and location and click **Create project**.



Nhost now creates your backend. It should take less than a minute. Once completed, go to your project to see your project's dashboard.



That's it! We now have all the necessary backend infrastructure to build our app.
But first, we need to create a table and set permissions to store our todos.

## Next step

[Todos Table](/quick-start/todos-table)

---

## File: src/pages/quick-start/todos-table.mdx

---
title: "Todos Table"
---

We need a table to store the todos that our application will manage, and also correct permissions on querying and inserting them. Hasura Console to the rescue.

> Hasura Console is where you manage your project's database and GraphQL API.

## Hasura Console

Go to **Hasura**. Go ahead and copy Hasura's **Admin secret** and use it to login to the **Hasura console**.



If you are not familiar with the Hasura Console, now it is a good time to click around and explore.

## Create todos table

Click on **DATA** tab on the top menu, and click on **Create Table**.

We'll create a `todos` table:

| Name         | Type      | Default value     |
| :----------- | :-------- | :---------------- |
| id           | UUID      | gen_random_uuid() |
| created_at   | Timestamp | now()             |
| name         | Text      |                   |
| is_completed | Boolean   | false             |

For the `id` and `created_at` you should use the **Frequently used columns** option. This ensures correct name, type and default values for those columns. It's a quick way to get started creating a new table.



The other columns, `name` and `is_completed`, you need to add manually (see the image bellow). Make sure you set the **default value** for `is_completed` to `false`.



Scroll down and click **Add table**.

### Query Data

To make sure we have a working GraphQL API, we will now insert two todos. Click the **Insert Row** tab and create two todos by specifying a **name** and clicking on **Save** (see the animation bellow).



Once you've added the todos, go the GraphiQL tab to query the data. **Copy-and-paste** the following query and click the **play button**.

```graphql
query {
  todos {
    id
    created_at
    name
    is_completed
  }
}
```

You should see your todos to the right as a response.

## Permissions

Right now, the only way to query todos is by using the **admin** role with an admin-secret (`x-hasura-admin-secret`). We are going to change that behavior so that **anyone** (`public`) is able to insert and select todos.

In the Hasura Console, go to your **todos** table and click on **Permissions**. We will set **insert** and **select** permissions for the **public** role.

> The `public` role is used by users that are not logged in.

### Insert

**Row insert permissions** should be set to **Without any checks** and **Column insert permissions** should only have **name** checked.



### Select

**Row select permissions** should be set to **Without any checks** and **Column select permissions** should have all columns checked.



---

Anyone can now **insert** and **select** todos. This is not secure, but it's a good start. We will secure our backend later when we add authentication.

## Next

[Frontend Web App](/quick-start/frontend-web-app)

---

## File: src/pages/storage/api-reference.mdx

---
title: "API Reference for Nhost Storage"
---

| Endpoint                                                     | Method | Description                         |
| ------------------------------------------------------------ | ------ | ----------------------------------- |
| [`/storage/o/`](#get-file)                             | GET    | Get file                            |
| [`/storage/m/`](#get-file-metadata)                    | GET    | Get file metadata                   |
| [`/storage/o//`](#get-zip-of-all-files-in-folder)      | GET    | Get ZIP of all files in folder      |
| [`/storage/m//`](#get-metadata-of-all-files-in-folder) | GET    | Get metadata of all files in folder |
| [`/storage/o//`](#upload-file)                         | POST   | Upload file                         |
| [`/storage/o//`](#delete-file)                         | DELETE | Delete file                         |

## Get file

Get file

### nhost-js-sdk

_Not needed, just access the file directly_

### Request

`GET /storage/o/`

### Response

```bash
<file>
```

## Get file metadata

Get file metadata

### nhost-js-sdk

```ts
storage.getMetadata(path: string);
```

### Request

`GET /storage/m/`

### Response

```json
{
  "key": "<path-to-file>",
  "AcceptRanges": "bytes",
  "LastModified": "2020-01-01T01:02:03.000Z",
  "ContentLength": 12345,
  "ETag": "Etag",
  "ContentType": "<content-type>",
  "Metadata": {
    "token": "<auto-generated-access-token-uuid>"
  }
}
```

## Get zip of all files in folder

Get zip of all files in folder.

### nhost-js-sdk

Just access the path directly.

### Request

`GET /storage/o//`

### Response

```bash
Downloadable list.zip file
```

## Get metadata of all files in a folder

Get metadata of all files in a folder.

### nhost-js-sdk

```ts
storage.getMetadata(path: string);
```

### Request

`GET /storage/m//`

### Response

```json
[
  {
    "key": "<path-to-file>",
    "AcceptRanges": "bytes",
    "LastModified": "2020-01-01T01:02:03.000Z",
    "ContentLength": 12345,
    "ETag": "Etag",
    "ContentType": "<content-type>",
    "Metadata": {
      "token": "<auto-generated-access-token-uuid>"
    }
  },
  {
    "key": "<other-path-to-file>",
    "AcceptRanges": "bytes",
    "LastModified": "2020-05-04T03:02:01.000Z",
    "ContentLength": 54321,
    "ETag": "Etag",
    "ContentType": "<content-type>",
    "Metadata": {
      "token": "<auto-generated-access-token-uuid>"
    }
  }
]
```

## Upload file

Upload file.

### nhost-js-sdk

````ts
storage.put(path: string, file: File);
```

### Request

`POST /storage/o/`

### Response

```json
{
  "key": "<path-to-file>",
  "AcceptRanges": "bytes",
  "LastModified": "2020-01-01T01:02:03.000Z",
  "ContentLength": 12345,
  "ETag": "Etag",
  "ContentType": "<content-type>",
  "Metadata": {
    "token": "<auto-generated-access-token-uuid>"
  }
}
````

## Delete file

Delete file.

### nhost-js-sdk

````ts
storage.delete(path: string);
```

### Request

`DELETE /storage/o/`

### Response

```bash
204 No Content
````

---

## File: src/pages/storage/image-transformation.mdx

---
title: "Image Transformation"
---

Transform images on-the-fly using query parameters. Cache headers are sent with the image for browsers to cache the image client-side.

## Example

<a
  href="https://backend-d32l5h6l.nhost.app/storage/o/public/example.jpg?w=800&q=90"
  target="_blank"
>
  https://backend-d32l5h6l.nhost.app/storage/o/public/example.jpg?w=800&q=90
</a>

Notice the `?w=800&q=90` at the end of the URL.

## Width

Specify width in pixels of the image. If no height (`h`) is specified, the image automatically calculates the height to keep the image's aspect ratio.

Query parameter: `w`.

|           |      |
| :-------- | :--: |
| Min value |  0   |
| Max value | 8192 |

## Height

Specify height in pixels of the image. If no width (`w`) is specified, the image automatically calculates the width to keep the image's aspect ratio.

Query parameter: `h`.

|            |      |
| :--------- | :--: |
| Min value  |  0   |
| Max height | 8192 |

## Quality

Specify the quality of the image.

Query parameter: `q`.

|           |     |
| :-------- | :-: |
| Min value |  0  |
| Max value | 100 |

## Format

Specify the preferred format of the requested image.

This parameter can be one of the following values: `webp`, `png`, `jpeg`, `auto`. When the auto value is given the image will be transformed to the `webp` format if the request header explicitly accepts `image/webp`, otherwise the default format will be returned.

Query parameter: `f`.

## Rounding

Give the image rounded corners

Query parameter: `r`.

This parameter can be either an integer or `full`, if the image has to be fully rounded (e.g. an avatar).

## Blur

Add a Gaussian blur to the image.

Query parameter: `b`.

|           |       |
| :-------- | :-:   |
| Min value |  0.3  |
| Max value | 1000  |

---

## File: src/pages/storage/index.mdx

---
title: "Nhost Storage"
---

Nhost Storage lets you handle user-generated files, such as videos and images.

You can define declarative [security rules](/storage/security-rules) based on the user, file, and other metadata.

All files in the storage are saved in [Minio S3](https://github.com/minio/minio), a high-performance object storage with a compatible AWS S3 API.

## Access

Storage is accessible with your backend URL under `/storage` (`https://backend-xxx.nhost.app/storage`).

After `/storage` you need to add either `/o` (object) or `/m` (metadata).

### Object

Object is used to access the actual file. Ex: `https://backend-xxx.nhost.app/storage/o/myfile.png`.

### Metadata

Metadata is used to access metadata about the file. Ex: `https://backend-xxx.nhost.app/storage/m/myfile.png`.

---

## File: src/pages/storage/security-rules.mdx

---
title: "Security Rules"
---

# Nhost Storage Security

## Rules

All files in Nhost Storage are protected with Security Rules.

With security rules, you can set granular access on **who** is allowed to do **what** based on the user and the file.

> All storage rules can be by-passed by admins using the Admin Secret. This is done by sending the Admin Secret as a header like: `x-admin-secret: <admin-secret>`. The Admin Secret is the same Admin Secret used to login to the Hasura console.

Security rules are written in yaml format.

Here is an example security rules.

```yaml
functions:
  isAuthenticated: "return !!request.auth"
  isOwner: "return !!request.auth && userId === request.auth['user-id']"
paths:
  /public*:
    read: "true"
    write: "isAuthenticated()"
  /users/:userId/:fileName:
    read: "public()"
    write: "isOwner(userId)"
```

In the above example we have the following rules:

- Anyone can read files located in the `/public*` folder. Because we use a `*` all paths that starts with `/public` will be covered by this rule. Ex: `/public/image.png` and `/public/other-path/cv.pdf`.
- Only logged in users are allowed to write to `/public*`.
- Anyone can read files from `/users/:userId/:fileName`. Ex: `/users/1/image.png`.
- Only logged in users can write to their own directory. Ex user with id `1` can upload a file to `/users/1/image.png` but not to `/users/2/image.png`.

### Structure

Storage Rules follows this structure:

```yaml
functions:
  functionName: "one line javascript that returns true or false"
paths:
  /path/to/file.png:
    operation: "true/false or functionName()"
    operation: "true/false or functionName()"
    operation: "true/false or functionName()"
  /path/to/folder:
    operation: "true/false or functionName()"
    operation: "true/false or functionName()"
    operation: "true/false or functionName()"
  /path/to/folder*:
    operation: "true/false or functionName()"
    operation: "true/false or functionName()"
    operation: "true/false or functionName()"
```

### Paths

Paths are specified under the `paths:` directive and specifies that path to the file or folder that you want to set rules for.

#### Path Variables

You can use path variables in the path to capture values specified at their position in the URL. These path variables can be used in the security rules functions.

Below is an example where we capture `:userId` as a variable in the URL and use that same `userId` variable to resolve `userId === request.auth['user-id']` in the `isOwner` function.

```yaml
functions:
  isOwner: "return !!request.auth && userId === request.auth['user-id']"
paths:
  /users/:userId/:fileName:
    write: "isOwner(userId)"
```

You can **not** nest paths like this:

```yaml
paths:
  /path/to/:
    read: "true/false or functionName()"
    /then/:
      read: "true/false or functionName()"
```

### Functions

You can use a function to resolve if a request should be allowed or not. A function can access information from the user making the request, file metadata and path variables.

A function must return `true` or `false`.

Functions are placed after the `functions:` directive and can be used after an operation like this:

```yaml
functions:
  public: "return true"
paths:
  /open-access*:
    read: "public()"
    write: "public()"
```

Functions can take arguments from the file path. In the example below we'll allow anyone to read a file located in `/users/:userId` but only users are allowed to write in their own folder with the name of their user id.

```yaml
functions:
  public: "return true"
  isOwner: "return !!request.auth && userId === request.auth['user-id']"
paths:
  /users/:userId/:fileName:
    read: "public()"
    write: "isOwner(userId)"
```

Who is allowed to do what given the rules above?

| User id       | Path                 | Operation     | Allowed? |
| ------------- | -------------------- | ------------- | -------- |
| 1             | `/users/1/image.png` | read (GET)    | Yes      |
| 1             | `/users/2/image.png` | read (GET)    | Yes      |
| 1             | `/users/1/image.png` | write (POST)  | Yes      |
| 1             | `/users/2/image.png` | write (POST)) | No       |
| Not logged in | `/users/2/image.png` | read (GET))   | Yes      |
| Not logged in | `/users/1/image.png` | write (POST)) | No       |
| Not logged in | `/users/2/image.png` | write (POST)) | No       |

#### Available variables

##### Path variables

Path variables can be accessed in function if they are present in the path (`/users/:myVariable`) and sent as a parameter to the function `isOwner(myVariable)`.

#### User

You can access user information at `request.auth['']`. All variables from the JWT-token claim can be accessed here without the `x-hasura`. For example, thi is how you access the user's id: `request.auth['user-id']`.

## Operations

The following operations can be used:

- `create` Upload new file
- `update` Overwrite existing file
- `get` - Get file
- `list` - List files in directory
- `delete` - Delete file

You can also use helper operations:

- `write` is the same as `create` and `update` and `delete`.
- `read` is the same as `get` and `list`.

## Access Token

When a file gets uploaded, Nhost Storage automatically generates a `token` (access token) for the file. The `token` will be added to the file's metadata.

Let's say you upload a file to `/data/document.txt` and get this as return data:

```json
{
  "key": "/data/document.txt",
  "AcceptRanges": "bytes",
  "LastModified": "2020-01-01T01:02:03.000Z",
  "ContentLength": 12345,
  "ETag": "Etag",
  "ContentType": "text/plain",
  "Metadata": {
    "token": "6a587e56-04d4-415d-bb2c-9a39491e31d2"
  }
}
```

And have the following storage rules:

```yaml
functions:
  validToken: 'return request.query.token === resource.Metadata.token'`
paths:
  /data*:
    read: 'validToken()'
```

Now, given our `validToken` function, anyone can access `/data/document.txt` with the `token` like this: `https://backend-xxx.nhost.app/storage/o/data/document.txt?token=6a587e56-04d4-415d-bb2c-9a39491e31d2`.

### Revoke access tokens

Access tokens can be revoked which means the old access token gets deleted and a new access token created. Only admins with the admin secret (same as Hasura's admin secret) can revoke tokens.

Request to revoke an access token:

### Request

`POST /storage/m/`

**Headers**

```json
x-admin-secret: <admin-secret>
```

**Body**

```json
{
  "action": "revoke-token"
}
```

### Response

```json
{
  "key": "<path-to-file>",
  "AcceptRanges": "bytes",
  "LastModified": "2020-01-01T01:02:03.000Z",
  "ContentLength": 12345,
  "ETag": "Etag",
  "ContentType": "<content-type>",
  "Metadata": {
    "token": "<new-auto-generated-access-token-uuid>"
  }
}
```

--- METRICS ---
- Files Extracted: 52
- Estimated Token Budget: ~28645 tokens
- Recency Window: Active (< 180 days)
- Canonical Reference: https://codewiki.google/github.com/nhost/docs
