Neil Thaiss · Feb 15, 2021

Can OAuth2 be used in a mirrored environment and what is the best practice?


We a currently looking at a way of securing any future REST API's using OAuth2, where the Authorisation Server (OAuth2) and Resource Server would be on the same server.

However, as we have mirrored environment the Resource Server, and therefore the Authorisation Server, need work with a Virtual IP Address and be able to failover to either of the mirror member servers.

Is that possible with OAuth2 and if so what are the best practices for this?

Any advise or guidance much appreciated.

Thank you.

Product version: HealthShare 2020.1
0 268
Discussion (7)2
Log in or sign up to continue

Hi Neil,

You should be able to use OAuth 2.0 in a mirrored HealthShare environment just like you would in a non-mirrored one, I don't know of any difference in best practices. Assuming that you have set up your Mirror VIP properly the fact that you are using a virtual IP address shouldn't matter. Clients trying to connect to your server only need to know the VIP and HealthShare should take care of the rest.

As for the failover question, all of the necessary components of OAuth 2.0 are stored in the HealthShare database (access tokens, client configurations and definitions, server configurations and definitions) and therefore should be mirrored across machines. This means that OAuth, once set up, should be good to go in case of a failover.

Have you looked at Using OAuth 2.0 and OpenID Connect in the HealthShare docs? That chapter has instructions and some best practices for using OAuth with HealthShare that I think apply to mirrored and non-mirrored setups just the same.

Hope this helps,


Hi McLean,

Thank you for your reply, very useful.

With regards to failover and the necessary OAuth2 components this was my biggest concern as I had assumed these components where store in the %SYS database, which isn't mirrored.

However, you saying that they are stored in the HealthShare database made me think and I can now see that they there is a global mapping for the HSSYS database, which can, I'm sure, be mirrored.

I have gone through a lot of documentation, but is there any particular links, that relate to this specific area that you could pass on?

Thanks again.


Hi Neil,

I come bearing bad news, which is that it looks like I was mistaken and the OAuth objects are all stored in the %SYS database after all. I'll have to look into this a little more because I have to imagine that OAuth can be used in a mirrored environment.

Not that it's necessarily helpful if the mirroring doesn't get sorted out, but this is the link to the OAuth HealthShare documentation: I was talking about.

I'll look into the mirroring question a bit more myself and see if I can find any better answers.



I found this discussion on mirroring parts of the %SYS database: There are a few interesting ideas here that might be worth checking out. For instance, seeing if you can make an OAUTH database and map the contents of the OAuth client/server/etc. tables into it. Or seeing if you can create export and import methods for OAuth things. However, the fact that this is the most relevant discussion I could find seems to confirm that there's no accepted way to mirror parts of the %SYS database.

The Server Migration Guide ( has notes on exporting from the IRISSYS database, though, it seems to focus on security settings, tasks, and custom items, none of which might be particularly helpful in this case. That said, it might be worth toying around with.

Sorry to have gotten your hopes up before, but hopefully some of this might help a little more.


Hi Neil,

Using OAuth2 in a mirrored environment would require some additional scripting to keep the configuration in sync between mirror members, since as you note it's stored in %SYS.

The Server Configuration on the auth server won't be changing much over time so I'd recommend writing an installation script that sets up all relevant configuration. Below are some snippets from an installation class I'm using on a Caché authorization server:

ClassMethod CreateServerConfiguration(pOrigNamespace As %String = "%SYS", Output interval As %Integer, Output server) As %Status
    Set server = ##class(OAuth2.Server.Configuration).Open(.tSC)
    If $IsObject(server) {
        Set tSC = server.Delete()
        If $$$ISERR(tSC) Quit tSC

    Set interval = 3600

    Set server = ##class(OAuth2.Server.Configuration).%New()
    Set server.Description = "Single Sign-On"
    Set issuer = ##class(OAuth2.Endpoint).%New()
    Set issuer.Host = ..#IssuerHost
    Set issuer.Prefix = ..#IssuerPrefix
    Set server.IssuerEndpoint = issuer

    Set scopes = ##class(%ArrayOfDataTypes).%New()
    Do scopes.SetAt("OpenID Connect","openid")
    Do scopes.SetAt("E-mail Address","email")
    Do scopes.SetAt("User Profile","profile")
    // Add whatever other custom scopes you need
    Set server.SupportedScopes = scopes

    Set server.AllowUnsupportedScope = 0
    Set server.SupportedGrantTypes = "APCI"
    Set server.ReturnRefreshToken = ""
    Set server.AudRequired = 0

    Set server.CustomizationRoles = "%DB_CACHESYS,%Manager"
    Set server.CustomizationNamespace = pOrigNamespace
    Set server.AuthenticateClass = ..#CustomAuthenticateClassName
    Set server.ValidateUserClass = ..#CustomValidateClassName
    Set server.GenerateTokenClass = "%OAuth2.Server.JWT"

    Set server.AccessTokenInterval = interval
    Set server.RefreshTokenInterval = 3*interval
    Set server.AuthorizationCodeInterval = 120
    Set server.ServerCredentials = ..#ServerX509Name
    Set server.SigningAlgorithm = "RS512"
    Set server.KeyAlgorithm = ""
    Set server.EncryptionAlgorithm = ""
    Set server.SSLConfiguration = ..#SSLConfig

    Quit server.Save()

ClassMethod CreateServerDefinition(Output server) As %Status
    Set tIssuer = ..#EndpointRoot

    Set server = ##class(OAuth2.ServerDefinition).%OpenId("singleton")
    Set:'$IsObject(server) server = ##class(OAuth2.ServerDefinition).%New()
    Set server.IssuerEndpoint = tIssuer
    Set server.AuthorizationEndpoint = tIssuer_"/authorize"
    Set server.TokenEndpoint = tIssuer_"/token"
    Set server.UserinfoEndpoint = tIssuer_"/userinfo"
    Set server.IntrospectionEndpoint = tIssuer_"/introspection"
    Set server.RevocationEndpoint = tIssuer_"/revocation"
    Set server.ServerCredentials = ..#ServerX509Name
    Quit server.%Save()

The client descriptions are likely to change over time as new clients are registered. I think to keep these in sync between mirror members you'll need to regularly export the relevant globals directly from the primary, transport them to the secondary, and import them into the %SYS namespace. Below are some methods that do the export and import:

ClassMethod ExportClientConfiguration(pDestFile As %String) As %Status
    new $namespace
    set $namespace = "%SYS"
    for type = "D","I" {
        set tList("OAuth2.Server.Client"_type_".GBL") = ""
        set tList("OAuth2.Client.Metadata"_type_".GBL") = ""
    set tSC = ##class(%File).CreateDirectoryChain(##class(%File).GetDirectory(pDestFile))
    return:$$$ISERR(tSC) tSC
    return $System.OBJ.Export(.tList,pDestFile,,.errorlog)

ClassMethod ImportClientConfiguration(pSourceFile As %String) As %Status
    new $namespace
    set $namespace = "%SYS"
    return $System.OBJ.Load(.pSourceFile,,.errorlog)

You could use a task to do this regularly on a short schedule.

Hi Pravin,

Thank you for your very detailed answer.

However, on investigation, I found that I didn't need any of this, as all the client and server configurations are stored in the HSSYS database, as are the access tokens, when they are created.

The %SYS namespace then contains a global mapping for OAuth2.* from the HSSYS database.

So, by mirroring the HSSYS database and setting the 'Customization namespace' to HSSYS in the OAuth2 server configuration, allows OAuth2 to continue to work after a failover.


Thank you Neil, I had the same issue and by mirroring the HSSYS database solved our issue. now we have the same ClientID and Secret between the DBs.

Much appreciated.