> ## Documentation Index
> Fetch the complete documentation index at: https://docs.superoffice.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Validating security tokens

> How to validate security tokens

There are a few of scenarios when applications must perform JSON Web Token (JWT) validation.

1. When the \[Authorization Code flow]\[5] is complete.

2. When an application obtains a system user ticket from the partner system user service endpoint.

3. When one of the outbound services begin an invocation cycle. Outbound services include Database Mirroring, ERPSync and Quote Connector.

Token validation establishes **trust** by the authentication mechanism. It ensures that:

* The token was issued by SuperOffice
* The token was issued to this user
* The user has granted the application access to the listed operation

## What is a JWT anyway?

JWT is short for JSON web token:

> A string representing a set of claims as a JSON object that is encoded in a JWS or JWE, enabling the claims to be digitally signed or MACed and/or encrypted. (\[RFC7519]\[2])

A JWT has 3 parts: header, payload, signature.

![ID Token][img1]

### JWT header

The header will show that the token type is JWT and which algorithm that has been used to **sign** it.

```javascript theme={null}
{
"typ":"JWT",
"alg":"HS256"
}
```

### JWT payload

The payload is the actual data of the JWT. It consists of a list of claims - each claim is a **name-value pair**.

A claim can be either \[standard OpenID Connect]\[14] or \[custom]\[8] (with its own namespace).

```javascript theme={null}
{
  "sub": "tony@superoffice.com",
  "http://schemes.superoffice.net/identity/associateid": "5",
  "http://schemes.superoffice.net/identity/identityprovider": "central-superid",
  "http://schemes.superoffice.net/identity/email": "tony@superoffice.com",
  "http://schemes.superoffice.net/identity/upn": "tony@superoffice.com",
  "http://schemes.superoffice.net/identity/is_administrator": "False",
  "http://schemes.superoffice.net/identity/ctx": "Cust26759",
  "http://schemes.superoffice.net/identity/company_name": "Tonys Developer Network",
  "http://schemes.superoffice.net/identity/serial": "1801550193",
  "http://schemes.superoffice.net/identity/netserver_url": "https://sod.superoffice.com/Cust26759/Remote/Services86/",
  "http://schemes.superoffice.net/identity/webapi_url": "https://sod.superoffice.com/Cust26759/api/",
  "http://schemes.superoffice.net/identity/system_token": "SuperOffice DevNet Node OIDC-8k8Q7DmBgo",
  "iat": "1581665207",
  "http://schemes.superoffice.net/identity/initials": "TY",
  "http://schemes.superoffice.net/identity/so_primary_email_address": "tony@superoffice.com",
  "nonce": "637172620046685267.NmU2ZmRjNTctYjU0ZS00ZDRlLThkNjgtOTBlZmY2N2QyYjc3MzYzZWE1YjctYTUxYS00NDM1LWE1YTEtNDEzYTMxNTgxMzA0",
  "nbf": 1581665147,
  "exp": 1581665507,
  "iss": "https://sod.superoffice.com",
  "aud": "6cf25376616343b38d14ddcd804f2891"
}
```

### SuperOffice-specific claims

SuperOffice offers the following in addition to the standard OAuth claims. The Federated ID column represents the \[legacy federated flow]\[11], which no one should be using any more.

<Note>
  The claims in the following table are all prefixed with `http://schemes.superoffice.net/identity/`
</Note>

| Claim name                 | Federated ID | OpenID Connect | Description                                                                                                                                                          |
| -------------------------- | :----------: | :------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `associateid`              |       X      |        X       | The current user's associate ID.                                                                                                                                     |
| `company_name`             |       X      |        X       | The current user's company name.                                                                                                                                     |
| `ctx`                      |       X      |        X       | The ctx claim is the context identifier, which is also the tenant identifier or Customer ID. Example Cust1234.                                                       |
| `email`                    |       X      |        X       | The current user's email address.                                                                                                                                    |
| `firstname`                |       X      |                | The current user's first name.                                                                                                                                       |
| `identityprovider`         |       X      |        X       | The identity provider responsible for authentication. Options:<br />SuperOffice AS (federated ID)<br />`https://sod.superoffice.com` (OpenID Connect)                |
| `initials`                 |       X      |        X       | The current user's full name initials. (added June 2019)                                                                                                             |
| `is_administrator`         |       X      |        X       | Determine whether the current user is an administrator.                                                                                                              |
| `lastname`                 |       X      |                | The current user's last name.                                                                                                                                        |
| `netserver_url`            |       X      |        X       | The URL to a tenant SOAP web service.<br />Often used in conjunction with SuperOffice \[.NET NuGet proxies]\[7].<br />New applications should always use the latest. |
| `remember_me_expires`      |       X      |        X       | Unused.                                                                                                                                                              |
| `serial`                   |       X      |        X       | The tenant database serial number.                                                                                                                                   |
| `so_primary_email_address` |       X      |        X       | The current user's primary email address. (added June 2019)                                                                                                          |
| `system_token`             |       X      |        X       | A unique identifier used to exchange for a system ticket.<br />Used for background processing, back-channel communications.                                          |
| `ticket`                   |       X      |                | A current user's unique identifier, used for authentication.                                                                                                         |
| `upn`                      |       X      |        X       | Specifies a user principal name (UPN).                                                                                                                               |
| `webapi_url`               |       X      |        X       | The URL to a tenant REST web services.                                                                                                                               |

### JWT signature

**Signatures** verify that the information was sent from the sender and that the information **has not been altered**.

## What does it mean to validate tokens?

1. Verify the JWT is well-formed (has 3 period-separated sections)?
2. Parse the string and extract the Base 64 encoded components - are they valid JSON?
3. Is the signature OK?
4. Are the standard claims OK? Check there is a required **sub** claim and other OIDC claims.
5. Check the namespace-specific claims.

If any of these tests fail, the JWT should be rejected and not trusted.

Various SuperOffice services define different validation parameters used for performing validation.

## How to validate security tokens

Security token validation is an important step to ensure the token has not been compromised between SuperOffice sending it and you receiving it.

Performing validation is a straightforward process that must occur for each response that was signed by SuperOffice.

There are a couple of options to perform the actual validation:

1. Use explicit validation.

   * Use physical \[SuperOffice certificates]\[4].
   * Use the \[OpenID Connect metadata endpoint]\[8] to get the public certificate information from the `jwks_uri` endpoint.

2. Use \[SuperOffice.WebApi]\[9] NuGet package written for .NET Standard 2.0.
   * This uses the \[OpenID Connect metadata endpoint]\[8].

3. Use \[SuperOffice.Online.Core]\[6] NuGet package for .NET Framework.

   * This requires \[SuperOffice certificates]\[4].

## Explicit validation

This option eliminates any dependency on third party libraries to perform validation. There are three components necessary to perform token validation:

* Issuer
* Audience
* Certificate

The values used to populate validation parameters will vary depending on which SuperOffice token is validated. The table below will help guide you.

### Validation parameters

| Scenario                   | Issuer                          | Audience                  | SigningKey         |
| -------------------------- | ------------------------------- | ------------------------- | ------------------ |
| OAuth 2.0 / OpenID Connect | `https://{env}.SuperOffice.com` | Application ID            | Public certificate |
| System User                | SuperOffice AS                  | spn:\{serial claim value} | Public certificate |
| Connectors                 | SuperOffice AS                  | spn:Application ID        | Public certificate |
| Database Mirroring         | SuperOffice AS                  | spn:Application ID        | Public certificate |

For ease of understanding, rather than hard-code these values in the code sample below, the issue and audience values are extracted from the token itself, then used to set the appropriate `TokenValidationParameters` properties.

<Tabs>
  <Tab title="Sample C# Validator">
    This sample code has a System.IdentityModel.Tokens.Jwt NuGet package dependency.

    ```csharp theme={null}
    namespace Example
    {
        /// <summary>
        /// SuperOffice jwt token validator
        /// </summary>
        internal class SampleValidator
        {
            public Microsoft.IdentityModel.Tokens.TokenValidationResult ValidateSuperOfficeToken(string token)
            {
                var securityTokenHandler =
                    new Microsoft.IdentityModel.JsonWebTokens.JsonWebTokenHandler();

                string issuer;
                string audience;

                // extract the ValidAudience claim value (database serial number).
                var securityToken = securityTokenHandler.ReadJsonWebToken(token);

                // get the audience from the token
                if (!securityToken.TryGetPayloadValue<string>("aud", out audience))
                {
                    throw new Microsoft.IdentityModel.Tokens.SecurityTokenException(
                        "Unable to read ValidAudience from token.");
                }

                // get the issuer from the token
                if (!securityToken.TryGetPayloadValue<string>("iss", out issuer))
                {
                    throw new Microsoft.IdentityModel.Tokens.SecurityTokenException(
                        "Unable to read ValidAudience from token.");
                }

                var validationParameters =
                    new Microsoft.IdentityModel.Tokens.TokenValidationParameters();
                validationParameters.ValidAudience = audience;
                validationParameters.ValidIssuer = issuer;

                // Option #1 *************************************************************
                // use the local SuperOffice public certificate (SuperOfficeFederatedLogin)

                var certPath = Path.Combine("Certificates", "SuperOfficeFederatedLogin.crt");
                var x509Cert = new System.Security.Cryptography.X509Certificates.X509Certificate2(certPath);
                validationParameters.IssuerSigningKey = new Microsoft.IdentityModel.Tokens.X509SecurityKey(x509Cert);

                // Option #2 *************************************************************
                // use the OpenID Connect Jwks endpoint to get the public certificate.

                validationParameters.IssuerSigningKeys = GetJsonWebKeys("sod");

                var result = securityTokenHandler.ValidateToken(token, validationParameters);

                if (result.Exception != null || !result.IsValid)
                {
                    throw new Microsoft.IdentityModel.Tokens.SecurityTokenValidationException(
                        "Failed to validate the token", result.Exception);
                }
                return result;
            }

            private IList<JsonWebKey> GetJsonWebKeys(string environment)
            {
                // example only... needs exception handing...!!!
                var client = new HttpClient();
                var jwksContent = client.GetStringAsync($"https://{environment}.superoffice.com/login/.well-known/jwks");
                return JsonWebKeySet.Create(jwksContent.Result).Keys;
            }
        }
    }
    ```
  </Tab>
</Tabs>

[img1]: /media/loc/en/api/authentication/id-token.png


## Related topics

- [How to override the certificate resolver](/en/api/authentication/online/certificates/override-resolver.md)
- [Security](/en/automation/crmscript/security/index.md)
- [Security requirements](/en/developer-portal/standard-app/requirements/security.md)
- [Troubleshooting Database Mirroring](/en/online/mirroring/troubleshooting.md)
- [Mobile CRM security in SuperOffice CRM Online](/en/mobile/security.md)
