Securely login to DHIS2 from a different domain

Hi all!

I am working on an app which may connect to multiple instances of DHIS2, or to other data sources entirely to help the user perform data mapping and alignment. As such it does not make sense to create it as an app platform app. However I still need to connect to DHIS2 and so I am looking for some guidance on how to login and then make authenticated requests in a secure way from a third party application.

It does not look like DHIS2 will provide a session cookie when it’s requested from a different url (as mentioned here)

UPDATE: Thanks @chase.freeman for the recommendation on using OAuth for this. I am still having issues though because at this step in the documentation I am still getting CORS issues when requesting a token from a different origin. This is particularly odd, because I am able to send a request to api/oAuth2Clients and get the secret required for the token request without a problem. Perhaps the CORS whitelist is not applying to the token endpoint? /uaa/oauth/token (no api in the path)

UPDATE: I have also tried using personal access tokens however I am always redirected to the login page when authenticating with these.

Minimal example repo (as one web app trying to connect to another) is here.

Any help is much appreciated!

Many thanks,
Pete

3 Likes

Hi @plinnegan !

OAuth can work, but only if the CORS allowlist is correctly configured to allow requests from the domain of your app. Is this not possible with your use-case?

The only way to connect to a DHIS2 server across domains without CORS blocking cross-domain requests is to proxy all DHIS2 API requests through a server you control. You can still use either OAuth or PATs to authenticate requests from this server component to the destination server(s).

I would strongly recommend to consider the security implications of this app, particularly when it comes to collecting and storing credentials to multiple instances. Happy to look at your use-case in more detail with you some time if you’re interested.

1 Like

Thanks for the response @austin I’m narrowing down the scope for now so the use case is just an app to help users align metadata between instances where for example country instances have taken from a shared metadata resource and modified over time, but still need to report to one central instance. So it could sit on one server as a DHIS2 web app, but would still need to connect to another.

For example two data sets which now have slightly different disaggregations and fields but need to be aligned.

OAuth does not seem to work, because when I request the token from the server I am trying to connect to I get a CORS error. However is seems specific to the /uaa/oauth/token endpoint, because I am able to make requests using basic authentication from the app to other endpoints like api/oAuth2Clients (to get the oAuth secret) without any problems. And the localhost where I am testing is definitely on the CORS whitelist for play for example. Is there some other list which needs to be modified as well?

1 Like

@plinnegan using OAuth securely requires a server for the client application, which is why /uaa/oauth/token has CORS rules which disallow access from a browser. Using basic authentication from the browser also isn’t recommended. Having a server component here is what I would recommend.

If your application cannot have an OAuth “resource server” component, you could prompt the user to create a Personal Access Token on the remote DHIS2 instance and then enter that PAT into your app. You could store this PAT in the User Data Store with the confidential: true flag.

3 Likes

Thanks for the clarifications and solutions @austin :+1:

Unfortunately PATs do not seem to work right now on 2.37 (or perhaps there is just something misleading in the documentation on how to use them), I have raised a JIRA, same problem as before, CORS issue even when the referer is on the CORS whitelist and the list of allowed referers in the PAT :frowning_face:

For those who may view this post later, as of 2.37 the parameter is called encrypt=true (at least according to the docs)

1 Like