Web App Security, Understanding the Meaning of the BFF Pattern
Tags: dotnet, security, architecture, webdev
Published: 2021-10-19 22:21:51


## Identity and security overview

![Identity server with BFF flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zknv6hfa2v5xsciokx09.png)

When it comes to security. There is a lot of guidance and also advice and commentary on why you should or should not use each approach. It's hard to understand all the different options and security issues they have.
</br>

You also have different clients (mobile/web/app) and each has different security requirements for managing, storing and processing data in the form of tokens, cookies or sessions.

At the end, your app may scale and not all options can be deployed as multiple instance nodes without additional changes to the app and infrastructure.

This means that you really need to make decisions at the beginning and ask questions like: *What are your customers?* and *What are your requirements?* and *What can be added to the system in the future?* and *How is it possible to deal with the chosen approach?* etc. etc..

This article is part of [opensource training](https://github.com/damikun/trouble-training).

### Authentication vs Authorization

- `Authentication` - process of verifying who a user is (identity).
- `Authorization` - process of checking what a user has access to (checking permissions to access a particular resource).

### Tokens vs Cookie and Sessions

Tokens, cookies and sessions can be interpreted as resources or tools used by various protocols/standards/patterns (OAuth, OpenID, BFF) to perform identity-related tasks.

It is important to understand the basics as they end up being used in combination.

In the end, you can wrap the JWT token in a cookie and use it with session data for 'authorization' and 'authentication'.


#### Cookies

Cookies can be understood as small blocks of data created by the server that are written once in the response and automatically resent with each subsequent request from the web browser until their lifetime expires.

They can be used for authentication/authorization or tracking and marketing purposes. And much more...

*IndentityServer cookies example:*
![IdnetityServer Cookies in web browsers](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hhat3oci7tks5ordi7i3.png)

There are 3 main properties of cookies:
- `HttpOnly` - An http-only cookie cannot be accessed by client-side APIs, such as JavaScript. The browser will not allow you to access this cookie from the front-end code.
- `Secure` A secure cookie can only be transferred over an encrypted HTTPS connection.
- `SameSite` 3 option values `Strict`, `Lax` or `None` - this tells the browser which domain and address the cookie can be sent to.

##### What is origin?

The origin is usually ip and port or domain name and subdomain name.

```
// This are different origins since subdomain are different
https://developer.mozilla.org
https://mozilla.org

// This are also different origins since port number is different
https://localhost:5001
https://localhost:7001
```
 
##### Another cookie definitions:
- `Session cookies` - Created only for the browser session (in memory) and deleted/lost after closing.
- `Third-party cookies` - Usually the domain attribute of a cookies matches the domain displayed in the address bar of the web browser. as `first-party cookies`. The `third-party cookies` does not match the current domain and is used as `tracking cookies` to track user activity.

#### Sessions

Session is used to temporarily store information on the server for use across multiple pages of the site. It is usually associated with a cookie that is used to identify the session stored on the server, but does not contain any data.

![Session diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nr4bir7bzcydmixnjnkg.png)

#### Tokens

Tokens are data elements that allow application systems to perform the authorization and authentication process. They are usually encoded as base64 strings.

There are several types of tokens:
- `access token` - Includes user claims and signs them with a secret. It uses JWT tokens.
- `refresh token` - Used to *"refresh "* and get a new 'access token' after its lifetime expires.
- `id token` - JSON encoded data about user profile information
- etc, etc...

##### JWT Tokens

JSON Web Token is an open standard that defines how information can be securely transferred between parties as a JSON object. 

They are used for `authorization` and `information exchange` as they provide a security proof that the information wrapped in them is valid and written by a trusted source.

You can easily write arbitrary data to tokens, sign that data, and then have clients use it to access server resources. The server can verify that the token was signed and is still valid.


**Basic JWT token flow example:**

</br>

![Auth diagram JWT token](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0uu0tv3bu64xqub2zytn.png)

**JWT content:**

![JWT token](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1vjb0fshk9j5p4t428g.png)

**JWT consist of 3 parts:**

- `Header` - Contains information such as the type of token (JWT) and the signing algorithm used, e.g. HMAC SHA256 or RSA.

    </br>
    ```json
    {
    "alg": "HS256",
    "typ": "JWT"
    }
    ```
- `Payload` - Securly signed data (claims)
    </br>
    ```json
    {
    "sub": "1234567890",
    "name": "John Doe",
    "admin": true
    }
    ```
- `Signature` - Encrypted header, the encrypted payload, a secret and signed by an algorithm specified in the header.
    </br>
    ```js
    HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    secret
    ```

    More additional info about JWT tokens can be found at: [official documentation](https://jwt.io/introduction).

    </br>
    
    The most commonly used token for authorizing access to APIs is the `Bearer` token.

    </br>

</br>  
### Identity protocols

There are several protocols/specifications available to manage your identity or authorization process.

This was necessary to standardize authentication and authorization between services and clients. So we can use different global identity/authentication providers like Facebook, Google (external/internal) and also standardize the way the process is implemented.

![Oauth and OpenId logo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34dq7t1svckqhucckvxv.jpg)

This demo focuses on the most commonly used protocols `OAuth` and `OpenID Connect`.

Both protocols use a JWT token by default to encrypt and sign sensitive data, or to verify that the request was sent from a trusted source. It is also possible to use cookies on the front end and let the back end do the session and token authorization for you.

You can also watch and learn from various talks:
- [OAuth 2.0 and OpenID Connect - [Nate Barbettini]](https://www.youtube.com/watch?v=996OiexHze0)
- [Introduction to OAuth 2.0 and OpenID Connect - [Philippe De Ryck]](https://www.youtube.com/watch?v=GyCL8AJUhww)

#### OAuth
Primarily used to authorize an app's access to a specific resource. This is done without having to share your password with external sites.

![Oauth slack grant prompt example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0nbibr408u3tok6cl3xc.png)

If you have ever signed in to a new app and agreed to access your contacts, calendar, etc., you have used *OAuth 2.0*. This protocol does not provide any information about the user's endpoint, just a token to access certain resources. You can read more about [OAuth at this document](https://auth0.com/docs/authorization/protocols/protocol-oauth2).

![Oauth is authorization not authentication](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jjkx0h704xxqzqvcrht.png)

OAuth generally provides clients with *"secure delegated access "* to certain resources. Imagine you are a Google user and an app wants to access your calendar data. This can be an example of a flow:

`OAuth` flow example:

![Oauth flow explain](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8zul81j4tw6id68xu4gb.png)

In the above example, an application like Slack, Jira, etc. only gets permission to access a specific resource (e.g. the calendar), but not the user itself, so profile data like username and email are not transferred and remain protected.

If you want to learn more about OAuth, you can watch the following presentations:
- [Introduction to OAuth 2.0 Flow - [Philippe De Ryck]](https://youtu.be/GyCL8AJUhww?t=655)

##### Token exchange flows

There are several ways in which `grant` can be substituted. The choice depends on what kind of client is requesting access and how much that client is trusted.

- Authorization code flow
- Flow of authorization code with PKCE
- Implicit Flow
- Client credentials flow

![Oauth grant flow choice](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8reo62cmv0vnuhddz5v.png) Image from [Okta](developer.okta.com)

#### OpenID Connect

OpenID is a protocol for decentralized authentication

A login used by multiple internal/external applications. If you used your Google or Facebook etc. to log in to an external web or app, then you used *`OpenID Connect`*.

OpenID Connect is based on *OAuth 2.0.* (OAuth is the underlying protocol and OpenId is the identity layer built on top of it) and also uses a JWT token called `id_token` which encapsulates identity claims in JSON format. For more information about OpenId, see [under this specification](https://openid.net/connect/).

`id_token` example:

```json
{
"iss": "http://server.example.com",
"sub": "248289761001",
"aud": "s6BhdRkqt3",
"nonce": "n-0S6_WzA2Mj",
"exp": 1311281970,
"iat": 1311280970,
"name": "Dalibor Kundrat",
"given_name": "Dalibor",
"family_name": "Kundrat",
"gender": "male",
"birthdate": "0000-10-31",
"email": "d.kundrat@example.com",
"picture": "http://example.com/somepicture_of_dalibor.jpg"
}
```

</br>

`OpenId` flow example:

![OpenId Flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vike727dcdowbuftytyr.png)

</br>

There are several flows that can be used with `OpenId`. You can read more about them [under this article](https://darutk.medium.com/diagrams-of-all-the-openid-connect-flows-6968e3990660).

Each `OpenId` server by specification provides multiple endpoints to interact with.

The URLs of all endpoints can be explored using the **global discovery endpoint**. Often referred to as *disco*. It is available under the path: `/.well-known/openid-configuration` and returns JSON *OpenID Connect* metadata related to the specified authorization server.

Example *disco* response:

```json
  {
   "issuer":"https://localhost:5001",
   "jwks_uri":"https://localhost:5001/.well-known/openid-configuration/jwks",
   "authorization_endpoint":"https://localhost:5001/connect/authorize",
   "token_endpoint":"https://localhost:5001/connect/token",
   "userinfo_endpoint":"https://localhost:5001/connect/userinfo",
   "end_session_endpoint":"https://localhost:5001/connect/endsession",
   "check_session_iframe":"https://localhost:5001/connect/checksession",
   "revocation_endpoint":"https://localhost:5001/connect/revocation",
   "introspection_endpoint":"https://localhost:5001/connect/introspect",
   "device_authorization_endpoint":"https://localhost:5001/connect/deviceauthorization",
   "frontchannel_logout_supported":true,
   "frontchannel_logout_session_supported":true,
   "backchannel_logout_supported":true,
   "backchannel_logout_session_supported":true,
   "scopes_supported":["profile","openid","email","role", "offline_access" //etc..],
   "claims_supported":["name","family_name","profile","email", etc..],
   "grant_types_supported":["authorization_code","client_credentials", "refresh_token", //etc..],
   "response_types_supported":["code","token", "id_token","id_token token" //etc..],
   "response_modes_supported":["form_post","query","fragment"],
   "token_endpoint_auth_methods_supported":["client_secret_basic","client_secret_post" ],
   "id_token_signing_alg_values_supported":["RS256"],
   "subject_types_supported":["public" ],
   "code_challenge_methods_supported":["plain","S256"],
   "request_parameter_supported":true,
   "request_object_signing_alg_values_supported":["RS256","RS384" //etc..],
   "authorization_response_iss_parameter_supported":true
}
```

Main OpenId endpoints:

- `/authorization_endpoint` - interacting with the resource owner and obtaining an authorization permission.
- `/token_endpoint` - Obtain an access and/or ID token by presenting an authorization permission (code) or refresh token
- `/revocation_endpoint` - Revoke an access or refresh token.
- `/end_session_endpoint` - Ends the session associated with the specified ID token.
- `/userinfo_endpoint` - Provides information about the authenticated end user.

> &#10240;
> **NOTE:** All of these values in the discovery endpoint refer to the current server configuration. You can adjust or  enable/disable certain options in your code during idnetityserver configuration.
> &#10240;

### Backend for Frontend pattern (BFF)

BBF is a backend used by a particular front-end application.

Since endpoint APIs may have multiple clients with different requests, BFF can provide a client-specific backend mediator and act as a proxy that forwards and merges multiple requests to different service APIs.

![Backend for frontend - BFF example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lcxzmd5seiiwadqtvjwg.png)

> &#10240;
>Ok, we have cookies, tokens, and sessions. We use them for various authentication/authorization protocols (OpenId, OAuth, etc.) **and what the hack BFF is good for.**?
>
> Answer is:
>- Security reasons
>- Architecture reasons 
> &#10240;

#### Security reasons

In recent years, it was common to implement OpenID Connect for SPAs in Javascript (React, Angular, Vue...), and this is no longer recommended:
- Using access tokens in the browser has more security risks than using secure cookies.
- A SPA is a public client and cannot keep a secret, as such a secret would be part of the JavaScript and could be accessible to anyone inspecting the source code.
- Recent browser changes to prevent tracking may result in 'third-party cookies' being dropped.
- It is not possible to store something securely in the browser for a long period of time, as it can be stolen by various attacks.

Due to the above issues, the best security recommendation for SPA is to **avoid storing tokens in the browser** and create a lightweight backend to help with this process, called Backend for Frontend pattern (BFF).

This way, you can still use `acces_tokens` to authorize access to all your APIs, but clients will use session cookies or tokens in case of mobile devices and BFF will proxy this sides.

BFF can be:
- `statefull` - stores tokens in memory and uses a session to manage them.
- `stateless` - stores the tokens in encrypted HTTP-only, same-page cookies.

#### Architectural reasons

When you design your application, you have several options on how to access APIs from clients (web/mobile/external).

1) A single API gateway that provides a single API for all clients 
2) A single API gateway that provides an API for each type of client 
3) A per-client API gateway that provides an API to each client. 

##### BFF vs API gateway

While an `API Gateway` **is a single entry point** into to the system for all clients, a `BFF` is only responsible for a **single type of client**.

![Backend for frontend vs API gateway](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i0cohsd854uh4lrx6aye.png)

#### BBF cookies termination and token isolation

As mentioned in the text, the most important thing:
- Avoid storing tokens in the browser. (**No tokens in the browser** policy).
- Store tokens on the server side and use encrypted/signed HTTP-only cookies.

Recommended BFF pattern to secure SPA frontends:

![Backend for frontend  (BFF) cookie and tokens flow + proxy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vfy6lp88thttytod09h.png)

- Using this, all communication from the SPA frontend to the authorization server now passes through the BFF and tokens do not reach the SPA.
- The BFF now issues session cookies. These are part of the request to APIs and are exchanged for an access token at the proxy level.
- Client-side cookies are terminated by the BFF proxy.

## What's next?

Next time I will show you concrete implementation of BFF.

## Repository
You can find the full source code of the app, including identity, distributed logging, tracing and monitoring, in the open source Github repo:

https://github.com/damikun/trouble-training