> For the complete documentation index, see [llms.txt](https://tutorial.specian.co.uk/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tutorial.specian.co.uk/backend/user-authentication.md).

# User authentication

Now that we can get the links saved, let's add a layer of security by using [jsonwebtoken](https://jwt.io/introduction/).

There are 2 important things you should always do:

* Hash password before storing them in the database. If you leak them, you won't expose the actual passwords.

![Source: http://www.commitstrip.com/en/2018/03/22/basic-functionality](/files/-LqHA4l-m1iGHTUTNHxS)

* Only store enough information in the JWT to identify the user. Anyone can read its content.

Try it yourself, take this token and paste it in [jwt.io](https://jwt.io).

```
eyJzZWNyZXQiOiIxMjMiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.OZ-CLQhIwvruoziWza1XEB4PwCNfMnlcljRt14_Zckw
```

![Anyone can read the content of a token](/files/-LqBwTmf73FJztKB0XvD)

{% hint style="danger" %}
Never store password in plain text.
{% endhint %}

{% hint style="danger" %}
Never put sensitive data in a JWT.
{% endhint %}

Install the required dependencies:

```
$ yarn add jsonwebtoken bcryptjs @types/jsonwebtoken @types/bcryptjs
```

We first going to create a GraphQL input to structure the data we receive:

{% code title="resolvers/UserAuthInput.ts" %}

```typescript
import { InputType, Field } from "type-graphql";

@InputType()
class UserAuthInput {
  @Field()
  emailAddress: string;

  @Field()
  password: string;
}

export { UserAuthInput };
```

{% endcode %}

Update the `User` entity to return the `jwt` with:

{% code title="entities/User.ts" %}

```typescript
class User extends Model<User> {
  // ...
  @Field({ nullable: true })
  jwt?: string;
}
```

{% endcode %}

Add your `jwtSecret` to the shared config:

```typescript
export interface SharedConfig {
  jwtSecret: string;
  // ...
}

export const sharedConfig: SharedConfig = {
  // ...
  jwtSecret: process.env.JWT_SECRET || "",
  // ...
};

```

And finally create the resolver:

```typescript
import { Resolver, Query, Mutation, Arg } from "type-graphql";
import * as bcrypt from "bcryptjs";
import { User } from "../../../../entities";
import { getUserEntity } from "../../../../containers";
import { UserAuthInput } from "./UserAuthInput";
import * as jwt from "jsonwebtoken";
import { config } from "../../../../config";

@Resolver(of => User)
class UserResolver {
  private readonly _UserEntity = getUserEntity();
  @Mutation(returns => User)
  async signIn(@Arg("input")
  {
    emailAddress,
    password
  }: UserAuthInput): Promise<User> {
    const user = await this._UserEntity.findOne({ where: { emailAddress } });
    if (!user) {
      throw new Error("User not found");
    }
    if (!bcrypt.compare(password, user.password)) {
      throw new Error("Invalid password");
    }
    user.jwt = jwt.sign({ id: user.id }, config.jwtSecret);
    return user;
  }
  @Mutation(returns => User)
  async signUp(@Arg("input")
  {
    emailAddress,
    password
  }: UserAuthInput): Promise<User> {
    if (await this._UserEntity.findOne({ where: { emailAddress } })) {
      throw new Error("User with this email address already exists.");
    }
    const salt = bcrypt.genSaltSync(10);
    try {
      const user = await this._UserEntity.create({
        emailAddress,
        password: bcrypt.hashSync(password, salt)
      });
      user.jwt = jwt.sign({ id: user.id }, config.jwtSecret);
      return user;
    } catch (error) {
      console.error("Cannot create user.", error);
      throw error;
    }
  }
}

export { UserResolver };
```

### Writing tests

Update `setupTests.ts` to require the environment variables:

{% code title="src/setupTests.ts" %}

```typescript
require('dotenv').config()
```

{% endcode %}

When building the schema, GraphQL will complain if we don't have any queries. For this reason, let's create a `Health` resolver and add it to our schema when testing.

{% code title="resolvers/Health.ts" %}

```typescript
import { Int, ObjectType, Query, Resolver, Field } from "type-graphql";

@ObjectType()
class Health {
  @Field(() => Int)
  ok: number;
}

@Resolver(of => Health)
class HealthResolver {
  @Query(returns => Health)
  async health(): Promise<Health> {
    return { ok: 1 };
  }
}

export { HealthResolver };
```

{% endcode %}

Finally, test the resolver:

```typescript
import { ApolloServerBase, gql } from "apollo-server-core";
import {
  createTestClient
} from "apollo-server-testing";
import { buildSchema } from "type-graphql";
import { UserResolver } from "./User";
import { setUserEntity } from "../../../../containers";
import { User } from "../../../../entities";
import { HealthResolver } from "..";
import * as jwt from 'jsonwebtoken'

describe("routers/GraphQL/Resolvers/User", () => {
  describe("mutation/signIn", () => {
    it("should return a jwt for this user", async () => {
      const schema = await buildSchema({
        resolvers: [HealthResolver, UserResolver]
      });
      const server = new ApolloServerBase({ schema });
      const testClient = createTestClient(server);
      const user = { emailAddress: "test1@mock.com", password: "123" };
      const findOne = jest.fn();
      findOne.mockResolvedValue({ ...user, id: 'userid', });
      setUserEntity(({ findOne } as unknown) as typeof User);

      const { data, errors } = await testClient.mutate({
        mutation: gql`
          mutation signIn($input: UserAuthInput!) {
            signIn(input: $input) {
              id
              emailAddress
              jwt
            }
          }
        `,
        variables: { input: user }
      });
      expect(errors).toBeUndefined();
      expect(data!.signIn).toMatchObject({ id: "userid", emailAddress: user.emailAddress })
      expect(jwt.decode(data!.signIn.jwt)).toMatchObject({ id: 'userid' })
    });
  });
  describe("mutation/signUp", () => {
    it("should create a user and return the jwt", async () => {
      const schema = await buildSchema({
        resolvers: [HealthResolver, UserResolver]
      });
      const server = new ApolloServerBase({ schema });
      const testClient = createTestClient(server);
      const user = { emailAddress: "test2@mock.com", password: "123" };
      const findOne = jest.fn();
      const create = jest.fn();
      create.mockResolvedValue({ id: "userid", ...user });
      findOne.mockResolvedValue(null);
      setUserEntity(({ findOne, create } as unknown) as typeof User);

      const { data, errors } = await testClient.mutate({
        mutation: gql`
          mutation signUp($input: UserAuthInput!) {
            signUp(input: $input) {
              id
              emailAddress
              jwt
            }
          }
        `,
        variables: { input: user }
      });
      expect(errors).toBeUndefined();
      expect(data!.signUp).toMatchObject({ id: "userid", emailAddress: user.emailAddress })
      expect(jwt.decode(data!.signUp.jwt)).toMatchObject({ id: 'userid' })
    });
  });
});
```

{% hint style="info" %}
Tests are running in parallel. We recreate the server for each test to avoid conflicts.
{% endhint %}

### Adding security to the links

How do we know which user just sent a request? GraphQL uses `context` to pass down information to all resolvers and we will use the `Authorization` header to send the JWT which each request.

### Populating the GraphQL context

{% code title="routers/GraphQL/index.ts" %}

```typescript
import "reflect-metadata";
import { ApolloServer } from "apollo-server-express";

import { Router } from "express";

import { buildSchema } from "type-graphql";
import * as resolvers from "./resolvers";

import * as jwt from "jsonwebtoken";
import { config } from "../../config";
import { User } from "../../entities";

export interface GraphQLContext {
  user?: User;
}

export class GraphQLRouter {
  public readonly router = Router();
  constructor() {
    this.buildSchema();
  }
  async buildSchema() {
    const schema = await buildSchema({
      resolvers: Object.values(resolvers),
      validate: false
    });
    const apolloServer = new ApolloServer({
      schema,
      context: ({ req }): GraphQLContext => {
        if (!req.headers.authorization) {
          return {};
        }
        if (req.headers.authorization.slice(0, 7).trim() !== "Bearer") {
          return {};
        }
        try {
          return {
            user: jwt.verify(
              req.headers.authorization.slice(7),
              config.jwtSecret
            ) as User
          };
        } catch (error) {
          return {};
        }
      }
    });
    apolloServer.applyMiddleware({ app: this.router, path: "/" });
  }
}
```

{% endcode %}

### Testing

We can mock the context when creating the test server:

```typescript
const server = new ApolloServerBase({
  schema,
  context: { user: { id: "userid" } }
});
```

### Getting the context from resolvers

Add the argument `@Ctx() context` to a resolver:

```typescript
@Mutation(returns => Link)
  async addLink(
    @Arg("input") input: LinkInput,
    @Ctx() context: GraphQLContext
  ): Promise<Link> {
    if (!context.user) {
      throw new Error("Unauthorised");
    }
    const link = await this._LinkEntity.create({
      ...input,
      userId: context.user.id
    });
    return link;
  }
```

### Adding headers in the playground

Use the tab `HTTP HEADERS` at the bottom left.

![](/files/-LqCKKanD3SmjCLwwEtE)

### Conclusion

The backend is now ready to interact with the frontend. We can interact safely with the database and we have enough to implement anything we might need.

A lot is going on in this chapter. Have look at this [Pull Request](https://github.com/florianherrengt/book-code/pull/2) to see all the changes with comments.

{% hint style="info" %}
[user-auth](https://github.com/florianherrengt/book-code/tree/user-auth) branch available on GitHub.
{% endhint %}
