# JWT Validation

> Implement JWT validation with KrakenD API Gateway to secure your APIs and prevent unauthorized access.

Source: https://www.krakend.io/docs/enterprise/authorization/jwt-validation/

**Protect endpoints from public usage** by validating JWT tokens generated by any industry-standard **OpenID Connect (OIDC)** integration.

Before digging any further, here are some answers to frequently asked questions:

1. **KrakenD does not generate the tokens itself**. Still, you can plug it into any SaaS or self-hosted OpenID Identity Provider (**IdP**) using industry standards (e.g., Auth0, Azure AD, Descope, Google Identity Platform/Firebase, Keycloak, etc.)
2. **KrakenD does not need to validate all calls using your IdP**. KrakenD validates every incoming call’s signature and **it doesn’t make token introspection** (asking for the IdP data about the token owner).
3. **If you don’t have an identity server**, you can still use your classic monolith/backend login system and adapt it to return a JWT payload (a simple JSON). From here, let KrakenD [sign the token for you](https://www.krakend.io/docs/enterprise/authorization/jwt-signing/) and start using tokens immediately.
4. **Your self-hosted identity server doesn’t need to be exposed to the Internet**, as it can live behind KrakenD and let the token generation requests be proxied through KrakenD.
5. **I have tokens generated by the provider XYZ, are they supported?** Yes. We still need to find a single major provider that doesn’t follow the JSON Web Encryption (RFC 7516), JSON Web Signature (RFC 7515), or JSON Web Token (RFC 7519) specifications.
6. **If you are new to JWT validation**, start reading the [JSON Web Tokens overview](https://www.krakend.io/docs/enterprise/authorization/jwt-overview/)

## JWK URL requirements

Whether you decide to load the public key that guarantees that a token is properly signed from a remote URL (`jwk_url`) or locally (`jwk_local_path`), you must use the **JWK Set Format** as described in the [RFC-7517](https://datatracker.ietf.org/doc/html/rfc7517#section-5). This means that your JWK file **must contain a `keys` field** with the array of keys you want to validate.

## JWT header requirements

Make sure the token header has `kid` and `alg`

When KrakenD decodes the `base64` token string passed in the `Bearer` or a cookie, it expects to find in its **header section** (NOT THE PAYLOAD!) the `alg` and `kid`. You can paste your token into the [JWT debugger](https://jwt.io/#debugger-io) and make sure these fields are under “header”.

The value provided in the `kid` must match with the `kid` declared at the `jwk_url` or `jwk_local_path`.

Here’s an example of the **header section** of a decoded token:

```json
{
    "alg": "RS256",
    "kid": "MDNGMjU2M0U3RERFQUEwOUUzQUMwQ0NBN0Y1RUY0OEIxNTRDM0IxMw"
}
```

The `alg` and `kid` values depend on your implementation, but they must be present.

The example above used [this public key](https://albert-test.auth0.com/.well-known/jwks.json). Notice how the `kid` matches the single key present in the JWK document and the token header.

**KrakenD is built with security in mind** and uses **JWS** (instead of plain JWT or JWE), and the `kid` points to the right key in the JWS. This is why this entry is mandatory to validate your tokens.

## Basic JWT validation

The JWT validation must be present inside every endpoint definition needing it. If several endpoints are going to require JWT validation, consider using the [flexible configuration](https://www.krakend.io/docs/enterprise/configuration/flexible-config/) to avoid repetitive declarations.

Enable the JWT validation by adding the namespace `"auth/validator"` inside the `extra_config` of the desired `endpoint`. Do not forget to add caching.

For instance, to protect the endpoint `/protected/resource`:

```JSON
{
    "endpoint": "/protected/resource",
    "extra_config": {
        "auth/validator": {
            "alg": "RS256",
            "audience": ["http://api.example.com"],
            "roles_key": "http://api.example.com/custom/roles",
            "roles": ["user", "admin"],
            "jwk_url": "https://albert-test.auth0.com/.well-known/jwks.json",
            "cache": true
        }
    },
    "backend": [
        {
        "url_pattern": "/"
        }
    ]
}
```

This configuration makes sure that:

- The signature of the token matches with the keys under the JWK URL
- The key from the identity server is cached to avoid hammering it
- The token is well-formed and didn’t expire
- The token has a valid signature
- The role of the user is either `user` or `admin` (taken from a key in the JWT payload named `http://api.example.com/custom/roles`)
- The token is not revoked in the bloom filter (see [revoking tokens](https://www.krakend.io/docs/enterprise/authorization/revoking-tokens/))

## JWT validation settings

The following settings are available for JWT validation. There are many options, although generally only the **fields `alg` and `jwk_url` or `jwk_local_path` are mandatory**, and the rest of the keys can be added or not at your best convenience or depending on other options.

These options are for the `extra_config`’s namespace `"auth/validator"` placed in every endpoint (use [flexible configuration](https://www.krakend.io/docs/enterprise/configuration/flexible-config/) to avoid code repetition):

##### Fields of JWT validator

\* required fields

Minimum configuration needs **one of**: `alg` + `jwk_local_path` , or `alg` + `jwk_url`

##### [`alg`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#alg "Click to copy link to alg")

The hashing algorithm used by the token issuer.

Possible values are: `"EdDSA"` , `"HS256"` , `"HS384"` , `"HS512"` , `"RS256"` , `"RS384"` , `"RS512"` , `"ES256"` , `"ES384"` , `"ES512"` , `"PS256"` , `"PS384"` , `"PS512"`

Defaults to `"RS256"`

##### [`audience`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#audience "Click to copy link to audience") array of strings

Reject tokens that do not contain ALL audiences declared in the list.

Example: `["audience1"]`

##### [`auth_header_name`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#auth_header_name "Click to copy link to auth_header_name") string

Allows to parse the token from a custom header.

Example: `"X-Custom-Auth"`

Defaults to `"Authorization"`

##### [`cache`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#cache "Click to copy link to cache") boolean

Set this value to `true` (recommended) to stop downloading keys on every request and store them in memory for the next `cache_duration` period and avoid hammering the key server, as recommended for performance. Do not use this flag when using `jwk_local_ca`.

Defaults to `false`

##### [`cache_duration`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#cache_duration "Click to copy link to cache_duration") integer

The cache duration in seconds when the `cache` is enabled. 15 minutes when unset.

Defaults to `900`

##### [`cipher_suites`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#cipher_suites "Click to copy link to cipher_suites") array

Override the default cipher suites. Use it if you want to enforce an even higher security standard.

Defaults to `[49199,49195,49200,49196,52392,52393]`

##### [`cookie_key`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#cookie_key "Click to copy link to cookie_key") string

Add the key name of the cookie containing the token when it is not passed in the headers

Example: `"cookie_jwt"`

##### [`cypher_key`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#cypher_key "Click to copy link to cypher_key") string

The cyphering key.

##### [`disable_jwk_security`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#disable_jwk_security "Click to copy link to disable_jwk_security") boolean

When true, disables security of the JWK client and allows insecure connections (plain HTTP) to download the keys. Useful for development environments.

Defaults to `false`

##### [`failed_jwk_key_cooldown`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#failed_jwk_key_cooldown "Click to copy link to failed_jwk_key_cooldown") string

When a request comes with a token declaring an unknown `kid` (or the key strategy you choose), and the JWK is in a remote destination, KrakenD downloads the JWK from the Identity Provider for its recognition. Suppose there is a network failure, or the key is not in the list (e.g., you rotated the keys without anticipation). In that case, you can tell the gateway not to contact the Identity Provider again during the time specified here. We recommend setting this value, even with a low time (e.g., `10s`), to prevent misconfigurations from hammering your Identity Providers. Any values under one second are ignored.

Specify units using `ns` (nanoseconds), `us` or `µs` (microseconds), `ms` (milliseconds), `s` (seconds), `m` (minutes), or `h` (hours).

Examples: `"1m"` , `"10s"` , `"1h"`

##### [`issuer`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#issuer "Click to copy link to issuer") string

When set, tokens not matching the issuer are rejected.

Example: `"issuer"`

##### [`jwk_fingerprints`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#jwk_fingerprints "Click to copy link to jwk_fingerprints") array of strings

A list of fingerprints (the certificate’s unique identifier) for certificate pinning and avoid man-in-the-middle attacks. Add fingerprints in base64 format.

##### [`jwk_local_ca`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#jwk_local_ca "Click to copy link to jwk_local_ca") string

Path to the CA’s certificate verifying a secure connection when downloading the JWK. Use when not recognized by the system (e.g., self-signed certificates).

##### [`jwk_local_path`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#jwk_local_path "Click to copy link to jwk_local_path") string

Local path to the JWK public keys, has preference over `jwk_url`. Instead of pointing to an external URL (with `jwk_url`), public keys are kept locally, in a plain JWK file (security alert!), or encrypted. When encrypted, also add `secret_url` and `cypher_key`.

Example: `"./jwk.txt"`

##### [`jwk_url`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#jwk_url "Click to copy link to jwk_url") string

The URL to the JWK endpoint with the public keys used to verify the token’s authenticity and integrity. Use with `cache` to avoid re-downloading the key on every request. Consider enabling [shared caching](https://www.krakend.io/docs/authorization/jwk-caching/) too. The identity server will receive an HTTP(s) request from KrakenD with a KrakenD user agent, and the identity server must reply with a JSON object and a content-type `application/jwk-set+json` or `application/json`.

Examples: `"https://some-domain.auth0.com/.well-known/jwks.json"` , `"http://KEYCLOAK:8080/auth/realms/master/protocol/openid-connect/certs"` , `"https://yourOktaBaseUrl/v1/keys"`

##### [`key_identify_strategy`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#key_identify_strategy "Click to copy link to key_identify_strategy")

Allows strategies other than `kid` to load keys.

Possible values are: `"kid"` , `"x5t"` , `"x5t#S256"` , `"kid_x5t"`

##### [`leeway`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#leeway "Click to copy link to leeway") string

A margin of time where you will accept an already expired token. You should not accept expired tokens other than enabling two environments that are not perfectly synchronized and have minor clock drifts to accept each other differences. Any value specified here will be rounded to seconds, with a minimum of one second.

Specify units using `ns` (nanoseconds), `us` or `µs` (microseconds), `ms` (milliseconds), `s` (seconds), `m` (minutes), or `h` (hours).

Examples: `"1m"` , `"1s"`

Defaults to `"1s"`

##### [`operation_debug`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#operation_debug "Click to copy link to operation_debug") boolean

When `true`, any JWT **validation operation** gets printed in the log with a level `ERROR`. You will see if a client does not have sufficient roles, the allowed claims, scopes, and other useful information.

Defaults to `false`

##### [`propagate_claims`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#propagate_claims "Click to copy link to propagate_claims") array of arrays

Enables passing claims in the backend’s request header. You can pass nested claims using the dot `.` operator. E.g.: `realm_access.roles`.

##### [`propagate_claims_preserve_array`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#propagate_claims_preserve_array "Click to copy link to propagate_claims_preserve_array") boolean

When set to `true`, the JWT claims that are propagated to the backend will preserve their array structure as multi-value headers, if applies. If set to `false`, arrays will be converted to comma-separated strings.

Defaults to `false`

##### [`roles`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#roles "Click to copy link to roles") array of strings

When set, the JWT token not having at least one of the listed roles is rejected.

##### [`roles_key`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#roles_key "Click to copy link to roles_key") string

When validating users through roles, provide the key name inside the JWT payload that lists their roles. If this key is nested inside another object, add `roles_key_is_nested` and use the dot notation `.` to traverse each level. E.g.: `resource_access.myclient.roles` represents the payload `{resource_access: { myclient: { roles: ["myrole"] } }`. Notice that the roles object you choose is a list, not a map.

Example: `"resource_access.myclient.roles"`

##### [`roles_key_is_nested`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#roles_key_is_nested "Click to copy link to roles_key_is_nested") boolean

If the roles key uses a nested object using the `.` dot notation, you must set it to `true` to traverse the object.

##### [`scopes`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#scopes "Click to copy link to scopes") array of strings

A list of scopes to validate. The token, after decoding it, can have the scopes declared as a space-separated list, e.g.: `"my_scopes": "resource1:action1 resource3:action7"` or inside a list, e.g.: `"my_scopes": ["resource1:action1","resource3:action7"]`.

##### [`scopes_key`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#scopes_key "Click to copy link to scopes_key") string

The key name where KrakenD can find the scopes. The key can be a nested object using the `.` dot notation, e.g.: `data.access.my_scopes`.

##### [`scopes_matcher`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#scopes_matcher "Click to copy link to scopes_matcher")

Defines if the user needs to have in its token at least one of the listed claims (`any`), or `all` of them.

Possible values are: `"any"` , `"all"`

Defaults to `"any"`

##### [`secret_url`](https://www.krakend.io/docs/enterprise/authorization/jwt-validation/#secret_url "Click to copy link to secret_url") string

An URL with a custom scheme using one of the supported providers (e.g.: `awskms://keyID`) (see providers).

Examples: `"base64key://smGbjm71Nxd1Ig5FS0wj9SlbzAIrnolCz9bQQ6uAhl4="` , `"awskms://keyID"` , `"azurekeyvault://keyID"` , `"gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]"` , `"hashivault://keyID"`

Schema: [https://www.krakend.io/schema/v3.0/auth/validator.json](https://www.krakend.io/schema/v3.0/auth/validator.json "JSON schema definition")

Here there is an example using an external `jwk_url`:

```json
{
    "endpoint": "/foo",
    "extra_config": {
        "auth/validator": {
            "alg": "RS256",
            "jwk_url": "https://url/to/jwks.json",
            "cache": true,
            "audience": [
                "audience1"
            ],
            "roles_key": "department",
            "roles_key_is_nested": false,
            "roles": [
                "sales",
                "development"
            ],
            "scopes_key": "my_scopes",
            "scopes_matcher": "any",
            "scopes": [
                "resource1:action1",
                "resource2:action1",
                "resource1:action2"
            ],
            "issuer": "http://my.api.com",
            "cookie_key": "TOKEN",
            "disable_jwk_security": true,
            "jwk_fingerprints": [
                "S3Jha2VuRCBpcyB0aGUgYmVzdCBnYXRld2F5LCBhbmQgeW91IGtub3cgaXQ=="
            ],
            "cipher_suites": [
                10, 47, 53
            ],
            "operation_debug": true
    }
}
}
```

Performance considerations

If you use cryptographic algorithms that require high computation such as `RS512`, make sure your KrakenD instances have a proper CPU setting. Additionally, enable `cache` to avoid hammering your identity servers and save internal network traffic.

### Caching keys

A crucial decision when using JWT is [defining a caching strategy](https://www.krakend.io/docs/enterprise/authorization/jwk-caching/) that works with your **key rotation** policy.

If you don’t set any caching option, KrakenD will default to the **more pessimistic scenario** where you rotate the keys continuously, and KrakenD needs to download the keys in the JWK URL every single time. In most cases, this option will **add a lot of pressure to your identity server**. Therefore, we encourage you to enable `cache` in each endpoint, and even better if you add the second-level shared cache in the JWK client with `shared_cache_duration`. For instance:

```json
{
    "version": 4,
    "extra_config": {
        "auth/validator": {
            "@comment": "Enable a JWK shared cache amongst all endpoints of 15 minutes",
            "shared_cache_duration": 900
        }
    },
    "endpoints": [{
      "endpoint": "/protected",
      "extra_config": {
        "auth/validator": {
            "cache": true,
            "cache_duration": 3600,
            "@comment": "Rest of the validator options omitted for simplicity"
        }
      }
    }]
}
```

[Read more about JWK caching](https://www.krakend.io/docs/enterprise/authorization/jwk-caching/)

### Validation process

KrakenD does the following validation to let users hit protected endpoints:

- The `jwk_url` must be accessible by KrakenD at all times ([caching is recommended](https://www.krakend.io/docs/enterprise/authorization/jwk-caching/))
- The token is [well formed](https://jwt.io/#debugger-io)
- The `kid` in the **token header** (not payload) is listed in the `jwk_url` or `jwk_local_path` under `keys`.
- The content of the JWK Keys (`k`) is **base64** urlencoded
- The algorithm `alg` is supported by KrakenD and matches exactly the one used in the endpoint definition.
- The token hasn’t expired
- The signature is valid.
- The given `issuer` matches (if present in the configuration), and is a *string*
- The given `audience` matches (if present in the configuration), and is a *string*
- The given claims are within the endpoint accepted `roles` (if present in the configuration))
- All numeric claims checking is represented as a float64 (decimal).

The configuration allows you to define the set of required roles. For example, a user who passes a token with roles `A` and `B`, can access an endpoint requiring `"roles": ["A","C"]` as it has one of the required options (`A`).

If the token is expired, the configuration inside the namespace is incorrect, the signature doesn’t match, the required claims do not match, or the token is revoked, a `401 Unauthorized` is returned.

When the token doesn’t include the defined ACL’s required roles, a `403 Forbidden` is returned.

When you generate tokens for end-users, make sure to set a **low expiration**. Tokens are supposed to have short lives and should expire in a few minutes or hours.

### Accepted providers for encrypting payloads

When using a `jwk_local_path`, the `secret_url` scheme accepts different providers:

#### Local secrets

The local secrets require an URL with the following scheme:

```
base64key://base64UrlEncondedContent
```

The URL host must be `base64 url encoded` and must decode to exactly 32 bytes. Here is an example of the `extra_config`:

```json
{
    "jwk_local_path":"./jwk.txt",
    "secret_url":"base64key://smGbjm71Nxd1Ig5FS0wj9SlbzAIrnolCz9bQQ6uAhl4=",
    "cypher_key":"gCERmfqHMoEu3+utqBa/R1oMZYIvh0OOKtJmnX/hDPDxbXCGXGvO3SF7B5FWxrJnRW7rnjGIV4eP2VLrYX2q9pJM49BpP+A9"
}
```

This config will use the key `smGbjm71Nxd1Ig5FS0wj9SlbzAIrnolCz9bQQ6uAhl4=` for decrypting de `cypher_key` (base64 standard enconded) and then decrypting the content of the file `./jwt.txt`.

See this test to [understand how to generate and encrypt payloads](https://github.com/krakend/krakend-jose/blob/master/jwk_test.go).

#### Amazon KMS

```
awskms://keyID
```

The URL Host + Path is used as the key ID, which can be an Amazon Resource Name (ARN), alias name, or alias ARN. Note that ARNs may contain “:” characters, which cannot be escaped in the Host part of a URL, so you should use the `awskms:///<ARN>` form.

[More information about AWS KMS](https://docs.aws.amazon.com/kms/latest/developerguide/viewing-keys.html#find-cmk-id-arn)

#### Azure’s Key Vault

```
azurekeyvault://keyID
```

The credentials are taken from the environment unless the `AZURE_KEYVAULT_AUTH_VIA_CLI` environment variable is set to true, in which case it uses the `az` command line.

[More information about Azure Key Vault](https://docs.microsoft.com/en-us/azure/key-vault/general/basic-concepts)

#### Google Cloud KMS

```
gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]
```

You can take the URL [from the GCP console](https://cloud.google.com/kms/docs/object-hierarchy#key).

#### Hashicorp’s Vault

```
hashivault://keyID
```

Environment variables `VAULT_SERVER_URL` and `VAULT_SERVER_TOKEN` are used.

## Passing claims to the backend URL

Since KrakenD 1.2.0, it is possible to use data present in the claims to inject it into the backend’s final URL. The notation of the `url_pattern` field includes the parsing of `{JWT.some_claim}`, where `some_claim` is an attribute of your claim.

For instance, when your JWT payload is represented by something like this:

```json
{
    "sub": "1234567890",
    "name": "Mr. KrakenD"
}
```

Having a `backend` defined with:

```json
{
    "url_pattern": "/foo/{JWT.sub}",
    "method": "POST"
}
```

The call to your backend would produce the request:

```nginx
POST /foo/1234567890
```

Keep in mind that this syntax in the `url_pattern` field is only available if the backend loads the extra\_config `"auth/validator"` and that **it does not work with nested attributes** in the payload.

If KrakenD can’t replace the claim’s content for any reason, the backend receives a request to the literal URL `/foo/{JWT.sub}`.

## Propagate JWT claims as request headers

It is possible to forward claims in a JWT as request headers. It is a common use case to have, for instance, the sub claim added as an `X-User` header to the request. The propagation makes that other KrakenD components, such as rate-limiting, can work with information in the token.

**Important:** The endpoint `input_headers` needs to be set as well, so the backend can see it.

```json
{
    "endpoint": "/foo",
    "input_headers": ["X-User", "X-Role"],
    "extra_config": {
        "auth/validator": {
            "propagate_claims": [
                ["sub", "X-User"],
                ["realm_access.role", "X-Role"]
            ]
        }
    }
}
```

In this case, the `sub` claim’s value will be added as `x-user` header to the request. If the claim does not exist, the mapping is just skipped.

In addition, the nested property `role` (inside `realm_access`) is passed as an `x-role` header.

## A complete running example

The [KrakenD Playground](https://www.krakend.io/docs/enterprise/overview/playground/) demonstrates how to protect endpoints using JWT and includes two examples ready to use:

- Integration with an external third party using a [Single Page Application from Auth0](https://auth0.com/docs/applications/spa/)
- Integration with an internal identity provider service (mocked) using a symmetric key algorithm and a signer middleware.

To try it, [clone the playground](https://github.com/krakend/playground-community) and follow the README.

## Supported hashing algorithms and cipher suites

### Hashing algorithms

Accepted values for the `alg` field are:

- `EdDSA`: EdDSA
- `HS256`: HMAC using SHA-256
- `HS384`: HMAC using SHA-384
- `HS512`: HMAC using SHA-512
- `RS256`: RSASSA-PKCS-v1.5 using SHA-256
- `RS384`: RSASSA-PKCS-v1.5 using SHA-384
- `RS512`: RSASSA-PKCS-v1.5 using SHA-512
- `ES256`: ECDSA using P-256 and SHA-256
- `ES384`: ECDSA using P-384 and SHA-384
- `ES512`: ECDSA using P-521 and SHA-512
- `PS256`: RSASSA-PSS using SHA256 and MGF1-SHA256
- `PS384`: RSASSA-PSS using SHA384 and MGF1-SHA384
- `PS512`: RSASSA-PSS using SHA512 and MGF1-SHA512

### Cipher suites

Accepted values for cipher suites are:

- `5`: TLS\_RSA\_WITH\_RC4\_128\_SHA
- `10`: TLS\_RSA\_WITH\_3DES\_EDE\_CBC\_SHA
- `47`: TLS\_RSA\_WITH\_AES\_128\_CBC\_SHA
- `53`: TLS\_RSA\_WITH\_AES\_256\_CBC\_SHA
- `60`: TLS\_RSA\_WITH\_AES\_128\_CBC\_SHA256
- `156`: TLS\_RSA\_WITH\_AES\_128\_GCM\_SHA256
- `157`: TLS\_RSA\_WITH\_AES\_256\_GCM\_SHA384
- `49159`: TLS\_ECDHE\_ECDSA\_WITH\_RC4\_128\_SHA
- `49161`: TLS\_ECDHE\_ECDSA\_WITH\_AES\_128\_CBC\_SHA
- `49162`: TLS\_ECDHE\_ECDSA\_WITH\_AES\_256\_CBC\_SHA
- `49169`: TLS\_ECDHE\_RSA\_WITH\_RC4\_128\_SHA
- `49170`: TLS\_ECDHE\_RSA\_WITH\_3DES\_EDE\_CBC\_SHA
- `49171`: TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA
- `49172`: TLS\_ECDHE\_RSA\_WITH\_AES\_256\_CBC\_SHA
- `49187`: TLS\_ECDHE\_ECDSA\_WITH\_AES\_128\_CBC\_SHA256
- `49191`: TLS\_ECDHE\_RSA\_WITH\_AES\_128\_CBC\_SHA256

**Default suites** are:

- `49199`: TLS\_ECDHE\_RSA\_WITH\_AES\_128\_GCM\_SHA256
- `49195`: TLS\_ECDHE\_ECDSA\_WITH\_AES\_128\_GCM\_SHA256
- `49200`: TLS\_ECDHE\_RSA\_WITH\_AES\_256\_GCM\_SHA384
- `49196`: TLS\_ECDHE\_ECDSA\_WITH\_AES\_256\_GCM\_SHA384
- `52392`: TLS\_ECDHE\_RSA\_WITH\_CHACHA20\_POLY1305
- `52393`: TLS\_ECDHE\_ECDSA\_WITH\_CHACHA20\_POLY1305
