# Simple Auth Part II (React)

## Auth React-Side

Our job in React is simple enough:

1. send requests for login
2. if the login is successful, get the token and store it
3. from there on, send the token with each request
4. also, do something with the interface so the user knows they're logged in (show their avatar, etc)

## Some Utilities to Help Us

We have a little problem to solve first though. Needing to send the token sometimes means the url would be, at times `http://localhost:8080/contacts/list?order=email` and other times `http://localhost:8080/contacts/list?order=email&token=xxxxx`.

As we add parameters, this may becomes more and more cumbersome. Let's create a little function to handle that for us:

```javascript
// front/src/utils.js

/**
 * Takes an object like 
 *
```

* { name:'john', surname:'silver', guineas:400}
* \`\`\`
* and transforms it into a string like
* \`\`\`
* name=john\&surname=silver\&guineas=400
* \`\`\`
* This is a very simplistic function that will break on nested objects or arrays
* @param {Object} params An Object containing all the keys
* @returns {string} the query parameters string

  \*/

  export const objectToQuery = params => {

  return Object.keys(params)

  .filter( key => params\[key] !== undefined)

  .map( key => encodeURIComponent(key) + '=' + encodeURIComponent(params\[key]))

  .join('&')

  .trim();

  }

/\*\*

* creates a url string with a query object
* For example:
* \`\`\`
* const url = makeRequestUrl('/stardust',{a:1,username:'ziggy'})
* \`\`\`
* url in this case will be: `/stardust?a=1&username=ziggy`
* @param {String} path the path that you want to request
* @param {Object} params an object of parameters&#x20;
* @returns {string} the url

  \*/

  export const makeRequestUrl = (path, params) => {

  if(!params){ return path } // if no parameters were provided, return early

  const query = objectToQuery(params)

  if(query.length){

  &#x20;const has\_interrogation\_mark = path.indexOf('?') >= 0&#x20;

  &#x20;const url = path + (has\_interrogation\_mark ? '&' : '?') + query;

  &#x20;return url

  }

  return path

  }

  \`\`\`

While we're at it, let's create a shortcut so we avoid writing the full URL every time:

```javascript
// front/src/App.js
...
import { pause, makeRequestUrl } from "./utils.js";
...

const makeUrl = (path, params) => makeRequestUrl(`http://localhost:8080/${path}`,params)
...
```

Now, instead of this:

```javascript
const response = await fetch(`http://localhost:8080/contacts/list?order=${order}`);
```

we can write this:

```javascript
const url = makeUrl(`contacts/list`, {order, token: this.state.token})
const response = await fetch(url);
```

This "`token`" thing begins empty, but when we log in, it will be filled, and from that point on, it will be sent with each request

## Login and Logout

Those are particularly simple:

```javascript
// front/src/App.js
...
state = {
  ...
  token:null,
  nick:null
}
...
  login = async (username, password) => {
    try {
      const url = makeUrl(`login`, { username, password, token: this.state.token });
      const response = await fetch(url);
      const answer = await response.json();
      if (answer.success) {
        const { token, nick } = answer.result
        this.setState({ token, nick });
        toast(`successful login`);
      } else {
        this.setState({ error_message: answer.message });
        toast.error(answer.message);
      }
    } catch (err) {
      this.setState({ error_message: err.message });
      toast.error(err.message);
    }
  };
  logout = async token => {
    try {
      const url = makeUrl(`logout`, { token: this.state.token });
      const response = await fetch(url);
      const answer = await response.json();
      if (answer.success) {
        this.setState({ token:null, nick:null });
        toast(`successful logout`);
      } else {
        this.setState({ error_message: answer.message });
        toast.error(answer.message);
      }
    } catch (err) {
      this.setState({ error_message: err.message });
      toast.error(err.message);
    }
  };
...
```

One last thing to do, we want a form for logging in:

```javascript
onLoginSubmit = (evt) => {
  evt.preventDefault();
  const username = evt.target.username.value
  const password = evt.target.password.value
  if(!username){
    toast.error("username can't be empty");
    return
  }
  if(!password){
    toast.error("password can't be empty");
    return
  }
  this.login(username,password)
}
renderUser(){
  const { token } = this.state
  if(token){ // user is logged in
    return this.renderUserLoggedIn()
  }else{
    return this.renderUserLoggedOut()
  }
}
renderUserLoggedOut(){
  return (<form className="third" onSubmit={this.onLoginSubmit}>
    <input name="username" placeholder="username" type="text"/>
    <input name="password" placeholder="password" type="password"/>
    <input type="submit" value="ok"/>
  </form>)
}
renderUserLoggedIn(){
  const {nick} = this.state
  return (<div>Hello, {nick}! <button onClick={this.logout}>logout</button></div>)
}
...
```

Finally, change the previous `renderProfilePage` to:

```javascript
// front/src/App.js
...
// change the 
renderProfilePage = () => {
  return (
    <div>
      <p>profile page</p>
      {this.renderUser()}
    </div>
  );
};
...
```

Run the app!

We can verify this is working by trying a few usernames and passwords from the ones we've stored previously. For example, we can try:

```yaml
username: nina.williams@tek.ken
password: hapkido
```

We should see "hello anna!" with a logout button. Let's try the logout.

We just have to verify that we're receiving and sending the token.

Let's just add a button that accesses the user's page `/mypage`:

```javascript
// front/src/App.js
...
  getPersonalPageData = async () => {
    try {
      const url = makeUrl(`mypage`, { token: this.state.token });
      const response = await fetch(url);
      const answer = await response.json();
      if (answer.success) {
        const message = answer.result
        // we should see: "received from the server: 'ok, user <username> has access to this page'"
        toast(`received from the server: '${message}'`);
      } else {
        this.setState({ error_message: answer.message });
        toast.error(answer.message);
      }
    } catch (err) {
      this.setState({ error_message: err.message });
      toast.error(err.message);
    }
  }
...
  render(){
    ...
    <button onClick={this.getPersonalPageData}>get personal page data</button>
    ...
  }
```

Then try to click it; you should get an error. Log in, using, say:

```yaml
username: ken.masters@sf.er
password: shoryuken
```

You should get a message saying you accessed the page successfully.

We're done!

Almost.

If this was a real application, we'd probably want to store the users in our SQL database, and we'd probably want a way for user to sign up, reset their password, and so on. But, as we said at the beginning, all of this is too sensitive to reinvent it with every app, which is why we...

...are going to scrape most of what we've done here, and do production-grade authentication in the [next chapter](https://github.com/coditech/Documentation/tree/48c0bf3a27cfe19e399a3c6936cebcd010d7f58e/02_Tutorials/01_React_Beginner/07-auth2/readme.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://codi.gitbook.io/docs/02_tutorials/01_react_beginner/c.r.u.d/06.2-react-simple-auth.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
