dev.to clone using react-Hooks,Graphql-CodeGen, Apollo, Refresh-token, Authentication MiddleWare [Backend + FrontEnd](Part-2)
Tags: react, apollo, graphql, typescript
Published: 2019-10-18 13:52:08

Hello Community, Today I am writing 2 part of this article series in which I am trying to clone dev.to with minimum feature.It will be a prototype, in which user can signUp/signIn, create post & other features.
> I am doing it for just learning purpose.

> If you have not visited the first Part, please understand it first [Part-1](https://dev.to/vinodchauhan7/dev-to-clone-using-react-node-via-typescript-typegraphql-typeorm-backend-part-1-kmn)

###Technology Stack:
**NodeJs, ReactJs, Graphql, TypeOrm,TypeGraphql, Typescript, JWT, Apollo-server-express, Jest, Apollo-client, Apollo-link & much more..**

[GitHub Link](https://github.com/vinodchauhan7/dev.to-clone)

In second part of this series, I am able to make logic for **Refreshing tokens**, **Authenticated middlewares** for backend server. Additionally, I have also make my setup for React frontEnd with **Apollo-Client, React-Bootstrap, Styled-components, Graphql-CodeGen && much more**.

For ease, I have made 2 branches in my Git Repository to understand things more clearly :
         * [Part-4 Add authentication for graphql API and revoking refresh token logic](https://github.com/vinodchauhan7/dev.to-clone/tree/Part-4)
         * [Part-5 FrontEnd & backend setup](https://github.com/vinodchauhan7/dev.to-clone/tree/Part-5)

###Part-4(GitHub Branch)
 In this branch, We have done mainly 4 things which are as below :

**Token Version** : This 'tokenVersion' is saved with each user with default value of 0. It will be helpful to identify the authentication for Refresh-tokens, how many times user loggedIn and other things like ending all sessions of user.
```javascript
//For authentication, I am changing createRefreshToken method.
export const createRefreshToken = (user: User) => {
  return sign(
    { userId: user.id, tokenVersion: user.tokenVersion },
    process.env.REFRESH_TOKEN_SECRET!,
    {
      expiresIn: "7d"
    }
  );
```

**Refresh Token** : As we know, when we hit 'loginMutation' query then **server**  send us 'Refresh token' back as cookies. Now picture this, If a user loggedIn our **dev.to** clone and refresh the page then we need to make a mechanism to make it loggedIn and provide all services which he/she is authenticated for. To make this  possible, I am making a 'POST' api at our server which accepts cookies for the refresh-token and then it verifies it. If refresh-token verified successfully at server end then we again send the latest 'refresh-token' and 'access-token' to user so that user have not to login again and again unnecessarily.

```javascript
app.use(cookieParser());

  app.post("/refresh_token", async (req, res) => {
    const token = req.cookies.devId;
    if (!token) {
      console.log("token is not valid " + token);
      return res.send({ ok: false, accessToken: "" });
    }

    let payload: any = null;
    try {
      payload = await verify(token, process.env.REFRESH_TOKEN_SECRET!);
    } catch (err) {
      console.log(err);
      return res.send({ ok: false, accessToken: "" });
    }
    console.log("payload :: " + payload.userId);
    //token is valid and we can send him access token now.abnf
    const user = await User.findOne({ id: payload.userId });

    if (!user) {
      console.log("User not found");
      return res.send({ ok: false, accessToken: "" });
    }

    if (user.tokenVersion !== payload.tokenVersion) {
      return res.send({ ok: false, accessToken: "" });
    }

    //Referesh Token
    res.cookie("devId", createRefreshToken(user), {
      httpOnly: true
    });

    return res.send({ ok: true, accessToken: createAccessToken(user) });
  });
```

**Steps to follow :**
1) Login and get RefreshToken.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ou7h6j8mwmtmje4xh5g4.png)

2) Use postman for hitting REST API, and set refreshToken as cookie in it.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/xe1lou66epof9nxxznui.png)

3) Get the new AccessToken based on refresh-token.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/zj2jthpmcip2qp700uiz.png)

###Authentication Middleware :
Suppose we have some graphql queries which we want to be available for authenticated user only. To achieve this task, I am using middlewares from 'type-graphql'.

```javascript
 @Query(() => String)
  @UseMiddleware(isAuth) //Below is implementation
  me(@Ctx() { payload }: MyContext) {
    return `${payload!.userId}`;
  }

//isAuth.ts
export const isAuth: MiddlewareFn<MyContext> = ({ context }, next) => {
  const authorization = context.req.headers["authorization"];

  if (!authorization) {
    throw new Error("Not Authenticated");
  }

  try {
    const token = authorization.split(" ")[1];
    const payload = verify(token, process.env.ACCESS_TOKEN_SECRET!);
    context.payload = payload as any;
  } catch (err) {
    console.error(err);
    throw new Error("Not Authenticated");
  }
  return next();
};
```

###Revoking Refresh-token :
Picture this, Your "refresh-token" is not expired & you "forgot-password", then you dont want that anyone can authenticate himself for protected graphql queries or simple remove all its loggedIn sessions, then you can update the tokenVersion of the specific user so that he needs to verify himself with refreshTokens' tokenVersion.
```javascript
 @Mutation(() => Boolean)
  async revokeRefreshToken(@Arg("userId", () => Int) userId: number) {
    await getConnection()
      .getRepository(User)
      .increment({ id: userId }, "tokenVersion", 1);

    return true;
  }
```

##Part-5 Branch
In this branch, We have setup our react frontend app with command 
"npx create-react-app devto --typescript". After installation add following modules :
```javascript
yarn add apollo-boost @apollo/react-hooks graphql
yarn add -D @types/graphql
```
** Update your app.tsx file **
```javascript
import React from "react";
import ReactDOM from "react-dom";
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "@apollo/react-hooks";
import "bootstrap/dist/css/bootstrap.min.css";
import App from "./App";

const client = new ApolloClient({
  uri: "http://localhost:4000/graphql",
  credentials: "include"
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById("root1")
);
```

###Add graphql/CodeGen
```javascript
yarn add -D @graphql-codegen/cli
//then
npx graphql-codegen init
```
Steps to setup :
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/z81k772pqt2i0qyv2gdl.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/dvc9o5frtlpgnm3w60cg.png)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/e3paefq0ufx3xbobeiqr.png)


**Make your first graphql Query**
```javascript
query Hello {
  hello
}
```

**useHelloQuery() in app.tsx**
```javascript
import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { HeaderComponent } from "./components/Header/header.component";
import { GlobalStyle } from "./ui_components/GlobalStyle";
import { ColStyle, RowStyle } from "./ui_components/RowColStyle";
import { RegisterComponent } from "./components/User/Register.component";
import { useHelloQuery } from "./generated/graphql";
const App: React.FC = () => {
  const { data, loading } = useHelloQuery();

  if (loading || !data) {
    return <div>...</div>;
  }

  return (
    <>
      <GlobalStyle></GlobalStyle>
      <RowStyle>
        <ColStyle md={12}>
          <HeaderComponent />
        </ColStyle>
      </RowStyle>
      <RowStyle>
        <ColStyle md={12}>
          <Router>
            <Switch>
              <Route exact path="/" render={() => <div>{data.hello}</div>} />
              <Route exact path="/register" component={RegisterComponent} />
            </Switch>
          </Router>
        </ColStyle>
      </RowStyle>
    </>
  );
};

export default App;

``` 


Hope you will like this article, I will come back soon with more code :).