> For the complete documentation index, see [llms.txt](https://docs.cotter.app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.cotter.app/getting-access-token/verifying-jwt-tokens.md).

# Verifying JWT Tokens

## When to verify JWT Tokens?

In every API call to your backend server, you should include the `access_token` in the header of your requests. You need to **verify the `access_token` on each endpoint that you deem necessary**. Usually, you would **use a middleware so it automatically handles the verification** for each of your routes.

Some good JWT middleware libraries that you can use:

* Golang: <https://echo.labstack.com/cookbook/jwt>
* Node.js: <http://www.passportjs.org/>

### Don't have a backend server? Use the API.

{% content-ref url="/pages/-MIH\_Ye0dlvNM3xeG-xJ" %}
[Verify JWT Token using API (serverless)](/api-reference/oauth-tokens-api/verify-jwt-token-using-api-serverless.md)
{% endcontent-ref %}

## How to Verify the Access Token

The access token is a **JWT Token**, and it's signed using **Asymmetric Signing Algorithm ES256.** This means, unlike symmetric JWT tokens that are signed and verified using the same secret key, this asymmetric JWT Token is signed using a secret key that only Cotter knows, **but can be verified using a public key that you can find** [**here**](https://www.cotter.app/api/v0/token/jwks)**.**

* [ ] Make sure that the token is **not expired**
* [ ] Make sure that the `aud` matches your `API_KEY_ID`
* [ ] Check the `authentication_method` and `scopes` to match your API requirements (scopes are defaulted to `access` for now, and cannot be changed).
* [ ] Check that the JWT is well-formed.
* [ ] Check the signature.
* [ ] Check that the issuer `iss` = `https://www.cotter.app`

#### Checking other attributes of the user

If you want to check the user's email or phone number before allowing access, for example, you want to allow only emails with a specific domain to log in, you should do the check here.

## Third-Party JWT Libraries to Verify the Tokens

You can use third party libraries to verify JWT tokens. [Check the list of third party libraries here](https://jwt.io). Make sure you check for the algorithm that the JWT token uses.

#### For Cotter's JWT Tokens, use:

* Algorithm: `ES256`&#x20;
* Public Keys: <https://www.cotter.app/api/v0/token/jwks>&#x20;
  * take the key with `kid` = `SPACE_JWT_PUBLIC:8028AAA3-EC2D-4BAA-BE7A-7C8359CCB9F9`
  * Make sure you take the keys from this endpoint, and cache when necessary, but **don't hard-code it. The key may change.**

## Examples

Access tokens are usually included in `oauth_token.access_token` in the responses from the SDK, or in the Authorization Header.

{% tabs %}
{% tab title="Node.js" %}

```javascript
// Install Dependency
yarn add cotter-node

// Validate token
var cotterNode = require("cotter-node");
var cotterToken = require("cotter-token-js");

// Validate access token
const access_token = oauth_token.access_token;
try {
  var valid = await cotterNode.CotterValidateJWT(access_token);
} catch (e) {
  // Not Valid
  console.log(e)
}

// Read access token
let decoded = new cotterToken.CotterAccessToken(access_token);
console.log(decoded);

// Check that `aud` is your API KEY
const audience = decoded.getAudience();
if (audience !== YOUR_API_KEY_ID) {
  throw "Audience doesn't match"
}

// (Optional) Checking other attributes of the user
// Example, only allow my company domain to login
const email = decoded.getIdentifier();
if (email.split("@")[1] !== "cotter.app") {
  throw "Please use cotter business email instead of a personal email";
}
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
# Using https://github.com/nov/json-jwt

require 'net/http'
require 'json/jwt'


jwks_raw = Net::HTTP.get URI("https://www.cotter.app/api/v0/token/jwks")
jwk_set = JSON::JWK::Set.new(
  JSON.parse(
    jwks_raw
  )
)

access_token_string = 'eyJhbGciOiJFUzI1NiIsImtpZCI6IlNQQUNFX0pXVF9QVUJM...'
decoded_token = JSON::JWT.decode access_token_string, jwk_set

expected_aud = '<YOUR_API_KEY_ID>'
expected_iss = 'https://www.cotter.app'
unless (
  decoded_token[:iss] == expected_iss &&
  decoded_token[:aud] == expected_aud &&
  decoded_token[:sub].present? &&
  Time.at(decoded_token[:iat]).between?(5.minutes.ago, Time.now) &&
  Time.at(decoded_token[:exp]) > Time.now
)
  raise 'Access Token Verification Failed!'
end

print 'Cotter User id = ' + decoded_token[:sub]
```

{% endtab %}

{% tab title="Python (Flask)" %}

```python
# Install Dependencies
pip install cotter
pip install -U flask-cors

# Add a flask Endpoint
from flask import Flask
from flask import request
from flask_cors import CORS
from cotter import validate


app = Flask(__name__)
CORS(app)

@app.route('/login', methods=['POST'])
def login(name=None):
    req = request.get_json();

    # Getting access token and validate it
    token = req["oauth_token"]["access_token"]
    access_token_decoded = validate.validate_access_token(token, API_KEY_ID)

    # User Authenticated!
    # a) Either use Cotter's Access Token for your entire API authorization
    # OR
    # b) You can Generate your JWT Tokens or other session management here
    
    return resp;
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php 
require __DIR__ . '/vendor/autoload.php';
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\JWK;
use Jose\Component\Signature\Algorithm\ES256;
use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Jose\Component\Signature\Serializer\CompactSerializer;
use Jose\Component\Signature\JWSVerifier;

// The algorithm manager with the HS256 algorithm.
$algorithmManager = new AlgorithmManager([
  new ES256(),
]);

// We instantiate our JWS Verifier.
$jwsVerifier = new JWSVerifier(
  $algorithmManager
);

// The serializer manager. We only use the JWS Compact Serialization Mode.
$serializerManager = new JWSSerializerManager([
  new CompactSerializer(),
]);

$http = new GuzzleHttp\Client();
$response = $http->request('GET', 'https://www.cotter.app/api/v0/token/jwks', []);

$keys = json_decode((string) $response->getBody(), true);
$jwk = new JWK($keys["keys"][0]);


$token = "eyJhbGciOiJFUzI1NiIsImtpZCI6IlNQQU...";

// We try to load the token.
$jws = $serializerManager->unserialize($token);

// We verify the signature. This method does NOT check the header.
// The arguments are:
// - The JWS object,
// - The key,
// - The index of the signature to check. See 
$isVerified = $jwsVerifier->verifyWithKey($jws, $jwk, 0);

// continue your logic here
?>
```

{% endtab %}

{% tab title="Go" %}

```go
package middleware

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/google/uuid"
	"github.com/labstack/echo/v4"
	"gopkg.in/square/go-jose.v2"
	"gopkg.in/square/go-jose.v2/jwt"
)

// 👇 Enter your API KEY ID here
const API_KEY_ID = "YOUR_API_KEY_ID"
const JWKSURL = "https://www.cotter.app/api/v0/token/jwks"
const JWKSLookupKeyID = "SPACE_JWT_PUBLIC:8028AAA3-EC2D-4BAA-BE7A-7C8359CCB9F9"

func getKey() ([]byte, error) {
	// Fetch the JWT Public Key from the URL
	resp, err := http.Get(JWKSURL)
	if err != nil {
		return nil, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	// Parse the response into our keys struct
	keyset := make(map[string][]map[string]interface{})
	err = json.Unmarshal(body, &keyset)
	if err != nil {
		return nil, err
	}

	// It's a Key Set = there might be multiple keys
	// Find the key with kid = JWKSLookupKeyID
	if len(keyset["keys"]) <= 0 {
		return nil, errors.New("Key set is empty")
	}
	for _, k := range keyset["keys"] {
		if k["kid"] == JWKSLookupKeyID {
			key, err := json.Marshal(k)
			if err != nil {
				return nil, err
			}
			return key, nil
		}
	}
	return nil, errors.New("Cannot find key with kid")
}

// validateClientAccessToken validates access token created above
func validateClientAccessToken(accessToken string) (map[string]interface{}, error) {
	tok, err := jwt.ParseSigned(accessToken)
	if err != nil {
		return nil, errors.New("Fail parsing access token")
	}

	keys, err := getKey()
	if err != nil {
		return nil, err
	}
	key := jose.JSONWebKey{}
	key.UnmarshalJSON(keys)

	token := make(map[string]interface{})
	if err := tok.Claims(key, &token); err != nil {
		return nil, errors.New("Fail parsing access token to claims")
	}

	// Check that the aud is our API KEY ID
	apiKeyID, ok := token["aud"].(string)
	if !ok {
		return nil, errors.New("fail asserting aud from jwt.MapClaims")
	}
	if apiKeyID != API_KEY_ID {
		return nil, errors.New("Invalid aud, not meant for this api key id")
	}

	return token, nil
}

// This middleware assumes that your API endpoint looks like this:
// GET https://something.com/user/1
// Authorization: Bearer <access_token> 👈  We want to verify this

// CotterAuth is used to authenticate cotter access_tokens
func CotterAuth(next echo.HandlerFunc) echo.HandlerFunc {
	return func(ctx echo.Context) error {
		// get the access token from auth header
		reqToken := ctx.Request().Header.Get("Authorization")
		splitToken := strings.Split(reqToken, " ")
		if len(splitToken) != 2 {
			return errors.New("authorization header malformed")
		}
		tokenString := splitToken[1]

		// Validate that the access token and signature is valid
		token, err := validateClientAccessToken(tokenString)
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, err.Error())
		}

		// Read other claims, such as sub = Cotter User ID
		uIDStr, ok := token["sub"].(string)
		if !ok {
			return echo.NewHTTPError(http.StatusBadRequest, "fail asserting sub from jwt.MapClaims")
		}
		cotterUserID, err := uuid.Parse(uIDStr)
		if err != nil {
			return echo.NewHTTPError(http.StatusBadRequest, "invalid user id format in jwt claims")
		}
		fmt.Println("User logging in = ", cotterUserID)

		return next(ctx)
	}
}
```

{% endtab %}
{% endtabs %}
