Firely Auth Settings

Firely Auth can be configured extensively. This page lists all the settings and refers to some detail pages for some of the sections.

Settings files and variables

Just like Firely Server itself, Firely Auth features a hierarchy of settings files and variables. From lowest to highest priority:

  • appsettings.default.json - This comes with the binaries (and in the Docker container) and contains sensible defaults for most settings. You can change this file, but it might accidentally be overwritten upon a new release. Instead, put your settings in one of the following places.

  • appsettings.instance.json - This file is meant to override settings for this instance of Firely Auth. You can create this file yourself by copying (parts of) appsettings.default.json.

  • Environment variables with the prefix FIRELY_AUTH_ - Use environment variables to more easily configure settings from CI/CD pipelines, secure vaults etc.

Unsure how to name your variables? This works the same as with Firely Server settings with Environment Variables.

Sections

License

Use the License settings to set the location to the license file. A relative path is evaluated relative to the executable Firely.IdentityServer.Core.exe. You can use the same license file that came with Firely Server.

"License": {
  "LicenseFile": "./firelyserver-license.json"
},

Kestrel

Kestrel is the web server that is integrated into Firely Auth, just like for Firely Server. We recommend to run both behind a reverse proxy. Nevertheless you can control the settings for Kestrel.

"Kestrel": {
  "Endpoints": {
    "Http": {
      "Url": "http://localhost:5100"
    },
    "HttpsFromPem": {
      "Url": "https://localhost:5101",
      "SslProtocols": [ "Tls12", "Tls13" ],
      "Certificate": {
        "Path": "cert.pem",
        "KeyPath": "cert-key.pem"
      }
    }
  }
 },

These settings are not Firely Auth specific, and you can read more about them in the Microsoft documentation. In that documentation you can also read how to use the Https setting instead of HttpsFromPem to use a .pfx file for your SSL certificate.

Firely Server

Firely Auth hands out SMART on FHIR access tokens to access resources on Firely Server. To make Firely Server known to Firely Auth, fill in the FhirServerConfig:

"FhirServerConfig": {
   "Name": "Firely Server",
   "FHIR_BASE_URL": "http://localhost:4080"
},
  • Name: This name serves two purposes:

    • It can be added to the token as the value of the aud (audience) claim, if the client requests so. To have it accepted by Firely Server, set its SmartAuthorizationOptions:Audience setting to the same value.

    • It correlates with the clients allowed to access the token introspection endpoint (see below). Therefore it should match the value of TokenIntrospectionConfig:TokenIntrospectionResources:Name

  • FHIR_BASE_URL: This also has two uses:

    • A token can have a claim in the form of patient=<base>/Patient/123, to define the compartment the client is restricted to. This url is used as the base part in that url, and should match the base url of Firely Server, as it is accessed by the client.

    • If an aud parameter is provided in the authorize request, it has to match this url. E.g. in Postman you can provide this parameter by adding it to the Auth URL, like this: {{ids}}/connect/authorize?aud=http://localhost:4080 See the aud parameter in SMART on FHIR authorization request

Token types

Define for each client what type of token it can request.

 "TokenConfig": {
    "AccessTokenType": {
        "<ClientId>": "Jwt"
    }
},
  • <ClientId> should match one of the clients defined in ClientRegistrationConfig.

  • The value can be one of Jwt or Reference. Jwt means that this client will get self-contained Json Web Tokens. Reference means that this client will get reference tokens, that refer to the actual token kept in memory by Firely Auth. For more background see reference token.

E.g. "MySmartApp": "Reference"

Key management

"KeyManagementConfig": {
    "RSA_Config": {
        //"RSA_JWK": "<JSON Web Key>", // JSON Web Key of type RSA
        "SupportedAlgorithms": [
            "RS256",
            "RS384",
            "RS512"
        ]
    },
    "EC_Config": {
        //"JWK_ES256": "<JSON Web Key>", // JSON Web Key of type EC with crv P-256
        //"JWK_ES384": "<JSON Web Key>", // JSON Web Key of type EC with crv P-384
        //"JWK_ES512": "<JSON Web Key>", // JSON Web Key of type EC with crv P-512
        "SupportedAlgorithms": [
            "ES256",
            "ES384",
            "ES512"
        ]
    }
}

Firely Auth can work with multiple signature keys, used to sign access and other tokens.

  • RSA_Config: defines the RSA algorithms that are supported. In the config above all available algorithms are listed. Inferno tests require at least RS256 for all Single Patient tests, and for Bulk Data Export a RS384 or higher is needed.

    • RSA_JWK: allows to provide a pre-generated JSON Web Key. If this is not provided, Firely Auth will generate a key.

    • SupportedAlgorithms: limit this list to the algorithms that you need in your setup. In the config above all available algorithms are listed.

  • EC_Config: defines the EC (Elliptic Curve) algorithms that are supported. Inferno tests for Bulk Data Export require support for EC keys.

    • JWK_ES*: allows to provide a pre-generated JSON Web Key. If this is not provided, Firely Auth will generate a key for each of the supported algorithms.

    • SupportedAlgorithms: limit this list to the algorithms that you need in your setup. In the config above all available algorithms are listed.

Note that a single RSA key can be used for all supported algorithms. However, an EC key is tied to a specific algorithm, therefore you can supply a key for each of the algorithms.

For more background on JSON Web Keys see RFC 7517.

Token introspection

When using a reference token, Firely Server must verify the token with Firely Auth. Not just any system can ask for inspection though, therefore we list the systems that can with a name and a secret.

"TokenIntrospectionConfig": {
    "TokenIntrospectionResources": [{
        "Name": "Firely Server",
        "Secret": "<generate some hard to hack secret>"
    }]
},

This configuration is only needed if at least one client is configured to use reference tokens, see Token types.

User store

A user must be able to authenticate to Firely Auth before granting permissions to a client. Therefore we register the users with Firely Auth. Firely Auth supports two types of stores: In memory and SQL Server.

For the InMemory store, the users and their passwords are listed in plain text in this configuration. This is useful for testing, but not recommended for production use.

The SqlServer store stores the users and their encrypted passwords in a MS SQL Server database. Also the fhirUser and patient claims for each user can be stored. See SQL Server user store for details on setting up the database.

"UserStore": {
    "Type": "InMemory", // InMemory | SqlServer
    "InMemory": {
        "AllowedUsers": [
            {
                "Username": "bob",
                "Password": "password",
                "AdditionalClaims": [
                    {
                        "Name": "patient",
                        "Value": "Patient/a123"
                    }
                ]
            }
        ]
    },
    "SqlServer": {
        "ConnectionString": "<connection string here>"
    }
},
  • Type: select the type of store to use

  • InMemory: settings for the InMemory store

    • AllowedUsers: list of users

    • Username: login for a user

    • Password: password for the user, in clear text

    • AdditionalClaims: currently to be used for a single claim, to link the user to a Patient resource (and thereby to a Patient compartment), or a ‘user’ resource like a Practitioner in Firely Server.

      • Name: name of the claim, currently only patient and fhirUser are supported

      • Value: logical id of the related Patient or Practitioner resource (Patient/id) In the token this value will be expanded to an absolute url by prepending it with FhirServerConfig.FHIR_BASE_URL (see Firely Server).

  • SqlServer: settings for the SQL Server store

    • ConnectionString: connection string to the SQL Server database where the users are to be stored. This database and the schema therein must be created beforehand with a script.

Clients

The ClientRegistrationConfig is used to register the clients that are allowed to request access tokens from Firely Auth.

"ClientRegistrationConfig": {
    "AllowedClients": [
        {
            "ClientId": "Jv3nZkaxN36ucP33",
            "ClientName": "Postman",
            "Description": "Postman API testing tool",
            "Enabled": true,
            "RequireConsent": true,
            "RedirectUris": ["https://www.getpostman.com/oauth2/callback", "https://oauth.pstmn.io/v1/callback"],
            "ClientSecrets": [{"SecretType": "SharedSecret", "Secret": "re4&ih)+HQu~w"}], // SharedSecret, JWK
            "AllowedGrantTypes": ["client_credentials", "authorization_code"],
            "AllowedSmartLegacyActions": [],
            "AllowedSmartActions": ["c", "r", "u", "d", "s"],
            "AllowedSmartSubjects": [ "patient", "user", "system"],
            "AlwaysIncludeUserClaimsInIdToken": true,
            "RequirePkce": false,
            "AllowOfflineAccess": false,
            "AllowOnlineAccess": false,
            "AllowFirelySpecialScopes": true,
            "RequireClientSecret": true,
            "LaunchIds": [],
            "RefreshTokenLifetime": "30",
            "RequireMfa": true
        }
    ]
}

You register a client in the AllowedClients array. For each client you can configure these settings:

  • ClientId: string: unique identifier for this client. It should be known to the client as well

  • ClientName: string: human readable name for the client, it is shown on the consent page

  • Description: string: human readable description of the client

  • Enabled: true / false: simple switch to enable or disable a client (instead of removing it from the list)

  • RequireConsent: true / false: when true, Firely Auth will show the user a page for consent to granting the requested scopes to the client, otherwise all requested and valid scopes will be granted automatically.

  • RedirectUris: array of strings: url(s) on which Firely Auth will send the authorization code and access token. The client can specify one of the preregistered urls for a specific request.

  • ClientSecrets: secrets can be of type SharedSecret or JWK. You can have multiple of each, so you can accept two secrets for a short period of time to support key rotation and an update window for the client. The ClientSecrets section is ignored if RequireClientSecret is set to false.

    • SharedSecret: {"SecretType": "SharedSecret", "Secret": "<a secret string shared with the client>"} - this can be used for either client credentials or authorization code flow, but only with a confidential client.

    • JWK: {"SecretType": "JWK", "SecretUrl": "<JWKS url>"} - where the JWKS url hosts a JSON Web Key Set that can be retrieved by Firely Auth, see also JWK.

    • JWK: {"SecretType": "JWK", "Secret": "<JWK>"} - where JWK is the contents of a JWK. Use this if the client cannot host a url with a JWKS. Use one entry for each key in the keyset. Note that the JWK json structure is enbedded in a string, so you need to escape the quotes within the JWK. The url option above is recommended.

  • AllowedGrantTypes: array of either or both "client_credentials" and "authorization_code", referring to client credentials and authorization code flow. Use client credentials only for a confidential client.

  • AllowedSmartLegacyActions: Firely Auth can also still support SMART on FHIR v1, where the actions are read and write.

  • AllowedSmartActions: Actions on resources that can be granted in SMART on FHIR v2: c, r, u, d and/or s, see SMART on FHIR V2 scopes

  • AllowedSmartSubjects: Categories of ‘subjects’ to which resource actions can be granted. Can be system, user and/or patient

  • AlwaysIncludeUserClaimsInIdToken: true / false: When requesting both an id token and access token, should the user claims always be added to the id token instead of requiring the client to use the userinfo endpoint. Default is false

  • Require PKCE: true / false - see PKCE. true is recommended for a public client and can offer an extra layer of security for confidential client.

  • AllowOfflineAccess: true / false - Whether app can request refresh tokens while the user is online, see SMART on FHIR refresh tokens

  • AllowOnlineAccess: true / false - Whether app can request refresh tokens while the user is offline, see SMART on FHIR refresh tokens. A user is offline if he is logged out of Firely Auth, either manually or by expiration

  • AllowFirelySpecialScopes: true / false - Allow app to request scopes for Firely Server specific operations. Currently just ‘http://server.fire.ly/auth/scope/erase-operation

  • RequireClientSecret: true / false - A public client cannot hold a secret, and then this can be set to false. Then the ClientSecrets section is ignored. See also the note below.

  • LaunchIds: array of string - a ‘launch id’ could restrict access based on e.g. some currently active EHR context. Since Firely Auth is not connected to an EHR, this currently can only be set statically. Providing an empty array will make Firely Auth accept any launch id sent by the client (including none).

  • RefreshTokenLifetime: If the client is allowed to use a refresh token, how long should it be valid? The value is in days. You can also use HH:mm:ss for lower values.

  • RequireMfa: true / false, default is false. A user granting access to this client has to enable and use Multi Factor Authentication. See Using Multi Factor Authentication in Firely Auth

AllowedOrigins

By default CORS is enabled for all origins communicating over https. To adjust this, change the allowed origins in the AllowedOrigins setting. Wildcards can be used, for example to allow all ports: "https://localhost:*", or to allow all subdomains "https://*.fire.ly".

Inferno test settings

The Inferno test suite for ONC Certification (g)(10) Standardized API has tests using the “Inferno-Public” client. For this client, RequireClientSecret has to be set to false. The same suite also issues a launch id as part of test 3.3. For this to succeed, add the launch id that is used to the LaunchIds array of the ‘Inferno’ client.

Below you will find the settings that can act as a reference for testing this suite. On top of that you will need to arrange:

For hosting (either directly with Kestrel as shown below, or with a reverse proxy that sits in front)

  • SSL certificate for Firely Auth

  • SSL certificate for Firely Server

  • Configure both to use SSL protocols TLS 1.2 and 1.3

Necessary data:

  • Pre-load one version of US-Core conformance resources to the Firely Server administration endpoint

  • Pre-load the example resource of the same version of US-Core to the regular endpoint

We have a full walkthrough of Inferno testing available as a whitepaper, see our resources.

Firely Auth settings:

Put these settings in appsettings.instance.json next to the executable.

For Inferno you have to host it on https, with TLS 1.2 minimum. So you also need to provide a certificate for that (either to Kestrel as shown below, or to a reverse proxy that sits in front).

{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5100"
      },
      "HttpsFromPem": {
        "Url": "https://localhost:5101",
        "SslProtocols": [ "Tls12", "Tls13" ],
        "Certificate": {
          "Path": "cert.pem",
          "KeyPath": "cert-key.pem"
        }
      }
  // Use "Https" option instead if you want to use a .pfx file. See https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints
  }
 },

  "FhirServerConfig": {
    "Name": "Firely Server",
    "FHIR_BASE_URL": "<url where you host Firely Server>"
  },
  "TokenConfig": {
    "AccessTokenType": {
      "Inferno": "Reference",
      "Inferno-Public": "Reference"
    }
  },
  "KeyManagementConfig": {
    "RSA_Config": {
      "SupportedAlgorithms": [
        "RS256",
        "RS384",
        "RS512"
      ]
    },
    "EC_Config": {
      "SupportedAlgorithms": [
        "ES256",
        "ES384",
        "ES512"
      ]
    }
  },
  "TokenIntrospectionConfig": {
    "TokenIntrospectionResources": [{
      "Name": "Firely Server",
      "Secret": "secret"
    }]
  },
  "UserStore": {
    "Type": "InMemory", // InMemory | SqlServer
    "InMemory": {
      "AllowedUsers": [
        {
          "Username": "alice",
          "Password": "p@sSw0rd",
          "AdditionalClaims": [
            {
              "Name": "patient",
              "Value": "<id of a patient in your Firely Server, e.g. 'example'>"
            },
            {
              "Name": "fhirUser",
              "Value": "Practitioner/<id of a practitioner"
            }
          ]
        }
      ]
    },
  },
  "ClientRegistrationConfig": {
    "AllowedClients": [
      {
        "ClientId": "Inferno",
        "ClientName": "Inferno",
        "Enabled": true,
        "RequireConsent": true,
        "RedirectUris": [ "https://inferno.healthit.gov/suites/custom/smart/launch", "https://inferno.healthit.gov/suites/custom/smart/redirect" ],
        "AllowedGrantTypes": [ "authorization_code" ],
        "ClientSecrets": [
          {
            "SecretType": "SharedSecret",
            "Secret": "secret"
          }
        ],
        "AllowFirelySpecialScopes": false,
        "AllowedSmartLegacyActions": [ "read", "write", "*" ],
        "AllowedSmartActions": [ "c", "r", "u", "d", "s" ],
        "AllowedSmartSubjects": [ "patient", "user" ],
        "AlwaysIncludeUserClaimsInIdToken": true,
        "RequirePkce": false,
        "AllowOfflineAccess": true,
        "AllowOnlineAccess": false,
        "RequireClientSecret": true,
        "LaunchIds": ["<same id as for user>"],
        "RefreshTokenLifetime": "90"
      },
      {
        "ClientId": "Inferno-Public",
        "ClientName": "InfernoPublic",
        "Enabled": true,
        "RequireConsent": true,
        "RedirectUris": [ "https://inferno.healthit.gov/suites/custom/smart/launch", "https://inferno.healthit.gov/suites/custom/smart/redirect"],
        "AllowedGrantTypes": [ "authorization_code" ],
        "AllowFirelySpecialScopes": false,
        "AllowedSmartLegacyActions": [ "read", "write", "*" ],
        "AllowedSmartActions": [ "c", "r", "u", "d", "s" ],
        "AllowedSmartSubjects": [ "patient", "user" ],
        "AlwaysIncludeUserClaimsInIdToken": true,
        "RequirePkce": false,
        "AllowOfflineAccess": true,
        "AllowOnlineAccess": false,
        "LaunchIds": [],
        "RequireClientSecret": false,
        "RefreshTokenLifetime": "90"
      },
      {
        "ClientId": "Inferno-Bulk",
        "ClientName": "InfernoBulk",
        "Enabled": true,
        "RedirectUris": [ "https://inferno.healthit.gov/suites/custom/smart/launch", "https://inferno.healthit.gov/suites/custom/smart/redirect"],
        "AllowedGrantTypes": [ "authorization_code", "client_credentials" ],
        "AllowFirelySpecialScopes": false,
        "AllowedSmartLegacyActions": [ "read" ],
        "AllowedSmartActions": [ "c", "r", "u", "d", "s" ],
        "AllowedSmartSubjects": [ "system" ],
        "RequirePkce": false,
        "AllowOfflineAccess": true,
        "AllowOnlineAccess": false,
        "ClientSecrets": [
          {
            "SecretType": "JWK",
            "Secret": "{'e':'AQAB','kid':'b41528b6f37a9500edb8a905a595bdd7','kty':'RSA','n':'vjbIzTqiY8K8zApeNng5ekNNIxJfXAue9BjoMrZ9Qy9m7yIA-tf6muEupEXWhq70tC7vIGLqJJ4O8m7yiH8H2qklX2mCAMg3xG3nbykY2X7JXtW9P8VIdG0sAMt5aZQnUGCgSS3n0qaooGn2LUlTGIR88Qi-4Nrao9_3Ki3UCiICeCiAE224jGCg0OlQU6qj2gEB3o-DWJFlG_dz1y-Mxo5ivaeM0vWuodjDrp-aiabJcSF_dx26sdC9dZdBKXFDq0t19I9S9AyGpGDJwzGRtWHY6LsskNHLvo8Zb5AsJ9eRZKpnh30SYBZI9WHtzU85M9WQqdScR69Vyp-6Uhfbvw'}"
          },
          {
            "SecretType": "JWK",
            "Secret": "{'kty':'EC','crv':'P-384','x':'JQKTsV6PT5Szf4QtDA1qrs0EJ1pbimQmM2SKvzOlIAqlph3h1OHmZ2i7MXahIF2C','y':'bRWWQRJBgDa6CTgwofYrHjVGcO-A7WNEnu4oJA5OUJPPPpczgx1g2NsfinK-D2Rw','key_ops':['verify'],'ext':true,'kid':'4b49a739d1eb115b3225f4cf9beb6d1b','alg':'ES384'}"
          }
        ],
        "RequireClientSecret": true,
        "RefreshTokenLifetime": "90"
      }
    ]
  }
}

Firely Server settings

Put these settings in appsettings.instance.json, next to the executable.

For Inferno you have to host it on https, with TLS 1.2 minimum. So you also need to provide a certificate for that (either to Kestrel as shown below, or to a reverse proxy that sits in front).

"Hosting": {
  "HttpPort": 4080,
  "HttpsPort": 4081, // Enable this to use https
  "CertificateFile": "<your-certificate-file>.pfx", //Relevant when HttpsPort is present
  "CertificatePassword" : "<cert-pass>", // Relevant when HttpsPort is present
  "SslProtocols": [ "Tls12", "Tls13" ] // Relevant when HttpsPort is present.
},
"SmartAuthorizationOptions": {
  "Enabled": true,
  "Filters": [
    {
      "FilterType": "Patient",
      "FilterArgument": "_id=#patient#"
    }
  ],
  "Authority": "<url where Firely Auth is hosted>",
  "Audience": "Firely Server",
  "RequireHttpsToProvider": true,
  "Protected": {
    "InstanceLevelInteractions": "read, vread, update, patch, delete, history, conditional_delete, conditional_update, $validate, $meta, $meta-add, $meta-delete, $export, $everything, $erase",
    "TypeLevelInteractions": "create, search, history, conditional_create, compartment_type_search, $export, $lastn, $docref",
    "WholeSystemInteractions": "batch, transaction, history, search, compartment_system_search, $export, $exportstatus, $exportfilerequest"
  },
  "TokenIntrospection": {
      "ClientId": "Firely Server",
      "ClientSecret": "secret"
  },
  "ShowAuthorizationPII": false,
  //"AccessTokenScopeReplace": "-",
  "SmartCapabilities": [
    "LaunchStandalone",
    "LaunchEhr",
    //"AuthorizePost",
    "ClientPublic",
    "ClientConfidentialSymmetric",
    //"ClientConfidentialAsymmetric",
    "SsoOpenidConnect",
    "ContextStandalonePatient",
    "ContextStandaloneEncounter",
    "ContextEhrPatient",
    "ContextEhrEncounter",
    "PermissionPatient",
    "PermissionUser",
    "PermissionOffline",
    "PermissionOnline",
    "PermissionV1",
    //"PermissionV2",
    "ContextStyle",
    "ContextBanner"
  ]
},
//PipelineOptions: make sure that Vonk.Plugin.SoFv2 is enabled
"PipelineOptions": {
  "PluginDirectory": "./plugins",
  "Branches": [
    {
      "Path": "/",
      "Include": [
        //all other default plugins...
        "Vonk.Plugin.SoFv2",
      ],
      "Exclude": [
        //...
      ]
    },
    {
      "Path": "/administration",
      "Include": [
        //...
      ],
      "Exclude": [
        //...
      ]
    }
  ]
}

Inferno test settings

The Inferno test suite for ONC Certification (g)(10) Standardized API has tests using the “Inferno-Public” client. For this client, RequireClientSecret has to be set to false. The same suite also issues a launch id as part of test 3.3. For this to succeed, add the launch id that is used to the LaunchIds array of the ‘Inferno’ client.

Below you will find the settings that can act as a reference for testing this suite. On top of that you will need to arrange:

For hosting (either directly with Kestrel as shown below, or with a reverse proxy that sits in front)

  • SSL certificate for Firely Auth

  • SSL certificate for Firely Server

  • Configure both to use SSL protocols TLS 1.2 and 1.3

Necessary data:

  • Pre-load one version of US-Core conformance resources to the Firely Server administration endpoint

  • Pre-load the example resource of the same version of US-Core to the regular endpoint

We have a full walkthrough of Inferno testing available as a whitepaper, see our resources.

Firely Auth settings:

Put these settings in appsettings.instance.json next to the executable.

For Inferno you have to host it on https, with TLS 1.2 minimum. So you also need to provide a certificate for that (either to Kestrel as shown below, or to a reverse proxy that sits in front).

{
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5100"
      },
      "HttpsFromPem": {
        "Url": "https://localhost:5101",
        "SslProtocols": [ "Tls12", "Tls13" ],
        "Certificate": {
          "Path": "cert.pem",
          "KeyPath": "cert-key.pem"
        }
      }
  // Use "Https" option instead if you want to use a .pfx file. See https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints
  }
 },

  "FhirServerConfig": {
    "Name": "Firely Server",
    "FHIR_BASE_URL": "<url where you host Firely Server>"
  },
  "TokenConfig": {
    "AccessTokenType": {
      "Inferno": "Reference",
      "Inferno-Public": "Reference"
    }
  },
  "KeyManagementConfig": {
    "RSA_Config": {
      "SupportedAlgorithms": [
        "RS256",
        "RS384",
        "RS512"
      ]
    },
    "EC_Config": {
      "SupportedAlgorithms": [
        "ES256",
        "ES384",
        "ES512"
      ]
    }
  },
  "TokenIntrospectionConfig": {
    "TokenIntrospectionResources": [{
      "Name": "Firely Server",
      "Secret": "secret"
    }]
  },
  "UserStore": {
    "Type": "InMemory", // InMemory | SqlServer
    "InMemory": {
      "AllowedUsers": [
        {
          "Username": "alice",
          "Password": "p@sSw0rd",
          "AdditionalClaims": [
            {
              "Name": "patient",
              "Value": "<id of a patient in your Firely Server, e.g. 'example'>"
            },
            {
              "Name": "fhirUser",
              "Value": "Practitioner/<id of a practitioner"
            }
          ]
        }
      ]
    },
  },
  "ClientRegistrationConfig": {
    "AllowedClients": [
      {
        "ClientId": "Inferno",
        "ClientName": "Inferno",
        "Enabled": true,
        "RequireConsent": true,
        "RedirectUris": [ "https://inferno.healthit.gov/suites/custom/smart/launch", "https://inferno.healthit.gov/suites/custom/smart/redirect" ],
        "AllowedGrantTypes": [ "authorization_code" ],
        "ClientSecrets": [
          {
            "SecretType": "SharedSecret",
            "Secret": "secret"
          }
        ],
        "AllowFirelySpecialScopes": false,
        "AllowedSmartLegacyActions": [ "read", "write", "*" ],
        "AllowedSmartActions": [ "c", "r", "u", "d", "s" ],
        "AllowedSmartSubjects": [ "patient", "user" ],
        "AlwaysIncludeUserClaimsInIdToken": true,
        "RequirePkce": false,
        "AllowOfflineAccess": true,
        "AllowOnlineAccess": false,
        "RequireClientSecret": true,
        "LaunchIds": ["<same id as for user>"],
        "RefreshTokenLifetime": "90"
      },
      {
        "ClientId": "Inferno-Public",
        "ClientName": "InfernoPublic",
        "Enabled": true,
        "RequireConsent": true,
        "RedirectUris": [ "https://inferno.healthit.gov/suites/custom/smart/launch", "https://inferno.healthit.gov/suites/custom/smart/redirect"],
        "AllowedGrantTypes": [ "authorization_code" ],
        "AllowFirelySpecialScopes": false,
        "AllowedSmartLegacyActions": [ "read", "write", "*" ],
        "AllowedSmartActions": [ "c", "r", "u", "d", "s" ],
        "AllowedSmartSubjects": [ "patient", "user" ],
        "AlwaysIncludeUserClaimsInIdToken": true,
        "RequirePkce": false,
        "AllowOfflineAccess": true,
        "AllowOnlineAccess": false,
        "LaunchIds": [],
        "RequireClientSecret": false,
        "RefreshTokenLifetime": "90"
      },
      {
        "ClientId": "Inferno-Bulk",
        "ClientName": "InfernoBulk",
        "Enabled": true,
        "RedirectUris": [ "https://inferno.healthit.gov/suites/custom/smart/launch", "https://inferno.healthit.gov/suites/custom/smart/redirect"],
        "AllowedGrantTypes": [ "authorization_code", "client_credentials" ],
        "AllowFirelySpecialScopes": false,
        "AllowedSmartLegacyActions": [ "read" ],
        "AllowedSmartActions": [ "c", "r", "u", "d", "s" ],
        "AllowedSmartSubjects": [ "system" ],
        "RequirePkce": false,
        "AllowOfflineAccess": true,
        "AllowOnlineAccess": false,
        "ClientSecrets": [
          {
            "SecretType": "JWK",
            "Secret": "{'e':'AQAB','kid':'b41528b6f37a9500edb8a905a595bdd7','kty':'RSA','n':'vjbIzTqiY8K8zApeNng5ekNNIxJfXAue9BjoMrZ9Qy9m7yIA-tf6muEupEXWhq70tC7vIGLqJJ4O8m7yiH8H2qklX2mCAMg3xG3nbykY2X7JXtW9P8VIdG0sAMt5aZQnUGCgSS3n0qaooGn2LUlTGIR88Qi-4Nrao9_3Ki3UCiICeCiAE224jGCg0OlQU6qj2gEB3o-DWJFlG_dz1y-Mxo5ivaeM0vWuodjDrp-aiabJcSF_dx26sdC9dZdBKXFDq0t19I9S9AyGpGDJwzGRtWHY6LsskNHLvo8Zb5AsJ9eRZKpnh30SYBZI9WHtzU85M9WQqdScR69Vyp-6Uhfbvw'}"
          },
          {
            "SecretType": "JWK",
            "Secret": "{'kty':'EC','crv':'P-384','x':'JQKTsV6PT5Szf4QtDA1qrs0EJ1pbimQmM2SKvzOlIAqlph3h1OHmZ2i7MXahIF2C','y':'bRWWQRJBgDa6CTgwofYrHjVGcO-A7WNEnu4oJA5OUJPPPpczgx1g2NsfinK-D2Rw','key_ops':['verify'],'ext':true,'kid':'4b49a739d1eb115b3225f4cf9beb6d1b','alg':'ES384'}"
          }
        ],
        "RequireClientSecret": true,
        "RefreshTokenLifetime": "90"
      }
    ]
  }
}

Firely Server settings

Put these settings in appsettings.instance.json, next to the executable.

For Inferno you have to host it on https, with TLS 1.2 minimum. So you also need to provide a certificate for that (either to Kestrel as shown below, or to a reverse proxy that sits in front).

"Hosting": {
  "HttpPort": 4080,
  "HttpsPort": 4081, // Enable this to use https
  "CertificateFile": "<your-certificate-file>.pfx", //Relevant when HttpsPort is present
  "CertificatePassword" : "<cert-pass>", // Relevant when HttpsPort is present
  "SslProtocols": [ "Tls12", "Tls13" ] // Relevant when HttpsPort is present.
},
"SmartAuthorizationOptions": {
  "Enabled": true,
  "Filters": [
    {
      "FilterType": "Patient",
      "FilterArgument": "_id=#patient#"
    }
  ],
  "Authority": "<url where Firely Auth is hosted>",
  "Audience": "Firely Server",
  "RequireHttpsToProvider": true,
  "Protected": {
    "InstanceLevelInteractions": "read, vread, update, patch, delete, history, conditional_delete, conditional_update, $validate, $meta, $meta-add, $meta-delete, $export, $everything, $erase",
    "TypeLevelInteractions": "create, search, history, conditional_create, compartment_type_search, $export, $lastn, $docref",
    "WholeSystemInteractions": "batch, transaction, history, search, compartment_system_search, $export, $exportstatus, $exportfilerequest"
  },
  "TokenIntrospection": {
      "ClientId": "Firely Server",
      "ClientSecret": "secret"
  },
  "ShowAuthorizationPII": false,
  //"AccessTokenScopeReplace": "-",
  "SmartCapabilities": [
    "LaunchStandalone",
    "LaunchEhr",
    //"AuthorizePost",
    "ClientPublic",
    "ClientConfidentialSymmetric",
    //"ClientConfidentialAsymmetric",
    "SsoOpenidConnect",
    "ContextStandalonePatient",
    "ContextStandaloneEncounter",
    "ContextEhrPatient",
    "ContextEhrEncounter",
    "PermissionPatient",
    "PermissionUser",
    "PermissionOffline",
    "PermissionOnline",
    "PermissionV1",
    //"PermissionV2",
    "ContextStyle",
    "ContextBanner"
  ]
},
//PipelineOptions: make sure that Vonk.Plugin.SoFv2 is enabled
"PipelineOptions": {
  "PluginDirectory": "./plugins",
  "Branches": [
    {
      "Path": "/",
      "Include": [
        //all other default plugins...
        "Vonk.Plugin.SoFv2",
      ],
      "Exclude": [
        //...
      ]
    },
    {
      "Path": "/administration",
      "Include": [
        //...
      ],
      "Exclude": [
        //...
      ]
    }
  ]
}