# Authentication and Authorization

While often used interchangeably, authentication and authorization represent fundamentally different functions.

In simple terms, authentication is the process of verifying who a user is, while authorization is the process of verifying what they have access to.

![](https://1172597814-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MJ6Mj8gFbz9Ji6QL6Zi%2F-MM_kGfEjJI0941aAB35%2F-MM_kel0l4KTdYKFILgW%2Fras8no1uj4ih1ogzy89h.jpg?alt=media\&token=1a3063e6-7b64-4a05-a071-f212556cc199)

## Authentication

* Determines whether users are who they claim to be
* Challenges the user to validate credentials (for example, through passwords, answers to security questions, or facial recognition)
* Usually done before authorization
* Generally, transmits info through an ID Token

## Authorization

* Determines what users can and cannot access
* Verifies whether access is allowed through policies and rules
* Usually done after successful authentication
* Generally, transmits info through an Access Token

## Authorizing with JSON Web Token

For our authorization purposes, we'll use an NPM popular library: **jsonwebtoken**. More information at <https://www.npmjs.com/package/jsonwebtoken>

The library has two main functions:

1. **Generate a token,** `.sign()`, This receives multiple arguments.
   1. User identification information - which can be later on decoded
   2. A private key to  generate the hash tokens
   3. Options such as Expiration dates
2. **Decode an access token**, `.verify()`. This receives the following arguments:
   1. The access token
   2. The private key to decode it
   3. A callback function that returns an `error` object, in case the validity of the token fails, and the `decoded` object.

## Middleware

**Middleware** functions are functions that have access to the request object `req`, the response object `res`, and the `next` function in the application’s request-response cycle. The `next` function is a function in the Express router that, when invoked, executes the middleware succeeding the current middleware.

You can compose middleware functions using techniques like functional programming. This can make your middleware code more reusable and maintainable.

Middleware functions can perform the following tasks:

* Execute any code.
* Make changes to the request and the response objects.
* End the request-response cycle.
* Call the next middleware in the stack.

If the current middleware function does not end the request-response cycle, it must call `next()` to pass control to the next middleware function. Otherwise, the request will be left hanging.

Middleware functions can be used to perform a variety of tasks, such as:

* **Authentication and authorization:** Verify that users are logged in and have the necessary permissions to access certain resources.
* **Logging and error handling:** Log requests and handle errors gracefully.
* **Data validation:** Ensure that incoming data is valid and meets the application's requirements.
* **Request and response manipulation:** Modify the request object or response object before it is sent to the next middleware or route handler.

More info at [https://expressjs.com/en/guide/writing-middleware.html#:\~:text=The%20next%20function%20is%20a,request%20and%20the%20response%20objects.](https://expressjs.com/en/guide/writing-middleware.html)

## Basic Auth Example

{% tabs %}
{% tab title="server" %}
{% code overflow="wrap" %}

```javascript
let secret = 'serverKeptSecret'
const jwt = require('jsonwebtoken') //install from npm


// AUTHENTICATION LOGIC, IF PASSED, DO THE FOLLOWING
//...


// RETURNING THE AUTHORIZATION TOKEN
let tokenEncodedData = {
  email: loginEmail
} //we can encode identification information to use in future authorizations

response.success = true
response.token = jwt.sign(tokenEncodedData, secret, { expiresIn: 3600})
//expiration of the token is optional, if missing, the token won't expire
res.send(response)
//...

// MIDDLEWARE
// checks if the request token exists and has a proper structure
function verifyToken(req, res, next) {
  const bearerHeader = req.headers['authorization']

  if (typeof bearerHeader !== 'undefined') {
    const bearer = bearerHeader.split(' ')
    const bearerToken = bearer[1]
    req.token = bearerToken
    next()
  } else {
    res.sendStatus(401)
  }
}

// SERVING A PRIVATE RESOURCE
app.get('/private', verifyToken, (req, res) => {
// invokes the 'verifyToken' middleware
  jwt.verify(req.token, secret, (err, decoded) => {
  
    if (err) {
      if (err.expiredAt) {
      //if token expired, the err object will have an 'expiredAt' key
        res.send(({message: 'Your token has expired. Please re-authenticate'}))
      } else {
        res.send({message: 'You are NOT authorized to access this resource'})
      }
    } else {
      console.log(decoded.email)
      //we have access to the identification data used to generate the token
      //this way we can write a logic to access only the resources for which
      //a request is authorized
      res.send({message: 'Well kept secret'})
    }
  })
})
```

{% endcode %}
{% endtab %}

{% tab title="client" %}
{% code overflow="wrap" %}

```javascript
//setting global parameters for all HTTP requests
var globalRequestParameters = {    
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, *same-origin, omit
    headers: {
      'Content-Type': 'application/json'
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
    redirect: 'follow', // manual, *follow, error
    referrerPolicy: 'no-referrer',
  }
  
  const baseURL = 'http://localhost:3000/'
  
//AUTHENTICATION REQUEST
//...
if (res.success) { //authentication successful
    localStorage.setItem('token', res.token)
    } else {
    console.log('Authentication failed')
    }
//...


// REQUESTING A PRIVATE RESOURCE
function accessPrivateData() {
    let token = localStorage.getItem('token')
    //assuming the authorization token has been stored in localStorage
    if (token) {
        let parameters = { ...globalRequestParameters } //shallow object clone
        parameters.method = 'GET'
        parameters.headers.Authorization = 'Bearer ' + token
        //adding the token to the request
        fetch(baseURL + '/private', parameters)
        .then(res => res.json())
        .then(res => console.log(res)) //logging the private message
        //... optional error handling
    } else {
        console.log('no access token')
    }

}
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="info" %}

### Other popular AUTH methods.

**Session-based Authentication** uses server-side sessions to store user data, with a session ID stored in cookies. Compared to JWTs, it's more secure against token theft since sessions can be immediately invalidated, but requires server storage and can be challenging to scale across multiple servers.

**API Keys** are simple static tokens, often used for service-to-service authentication. They're simpler than JWTs but lack built-in expiration and payload capabilities. While easier to implement, they don't provide claims or user context like JWTs do.

**OAuth 2.0** is an authorization framework rather than pure authentication, using access tokens and refresh tokens. Unlike JWTs, it's more complex to implement but provides robust delegation of access rights and better security through short-lived access tokens and separate refresh tokens.

**SAML** uses XML-based tokens and is common in enterprise environments. Compared to JWTs, SAML tokens are more verbose and complex but provide richer security assertions. They're better suited for enterprise single sign-on but have higher overhead than JWTs.

**OpenID Connect** builds on OAuth 2.0, adding standardized authentication. It can use JWTs as ID tokens but adds a standardized protocol layer. It's more complex than pure JWT implementation but provides better standardization and security features.

**Basic Authentication** sends encoded credentials with each request. It's simpler than JWTs but less secure and lacks features like expiration or claims. It's mainly used for simple applications or development environments.
{% endhint %}

{% hint style="success" %}
**SSO (Single Sign-On)** enables one-time login across multiple applications using a central Identity Provider (IdP) like Okta, Azure AD or Google Workspace.

Basic flow:

1. User visits App A → redirects to IdP
2. User logs into IdP once
3. IdP sends signed token back to App A
4. When user visits App B, IdP sees existing session → auto-login

This works cross-domain through:

* SAML or OpenID Connect protocols
* Browser redirects
* Signed tokens (XML/JWT)
* IdP session cookies

Key benefits:

* One login for multiple apps
* Centralized user management
* Unified security policies
* Easy access revocation
* Audit logging
  {% endhint %}
