"Auth error Error: Not Found" when trying to authorize on Swagger

OpenEMR Version:
I’m using OpenEMR version 7.0.0

Browser:
Google Chrome

Operating System:
Windows 11

Situation:
I am using XAMPP to run Apache as my webserver and MySQL for database management.

I am running the following command to register my client - note that for testing purposes, I just need the Patient.read scope to work for now:

curl -X POST -k -H ‘Content-Type: application/json’ -i http://localhost/openemr/oauth2/default/registration --data ‘{
“application_type”: “private”,
“redirect_uris”:
[“http://localhost/openemr/swagger/oauth2-redirect.html”],
“client_name”: “My App”,
“token_endpoint_auth_method”: “client_secret_post”,
“contacts”: [“me@test.com”],
“scope”: “openid offline_access api:oemr api:fhir api:port user/Patient.read”
}’

I then go on Swagger at http://localhost/openemr/swagger/index.html to authorize using the response’s client_id and client_secret. This is where the first issue comes to light, where clicking the green Authorize button links me to
http://localhost/oauth2/default/authorize?response_type=code&client_id=fj3tIfVE1Byl1-5Lg5sjeHNeZ6EWRVxDEeZSQLlQXKs&redirect_uri=http%3A%2F%2Flocalhost%2Fopenemr%2Fswagger%2Foauth2-redirect.html&scope=openid%20offline_access%20launch%2Fpatient%20api%3Afhir%20user%2FPatient.read&state=RnJpIERlYyAzMCAyMDIyIDE1OjI3OjA5IEdNVC0wNTAwIChFYXN0ZXJuIFN0YW5kYXJkIFRpbWUp&code_challenge=iG8YFF_LqtgbgKZ8zXMGYBOYe5MkwccK5GEu0QvUCzw&code_challenge_method=S256

Notice that the url says http://localhost/oauth2 and NOT http://localhost/openemr/oauth2 - but manually inserting the “/openemr” takes me to the proper sign in prompt (the original URL took me to a “Not Found” error page). My intuition says that this may have something to do with the error I’m about to explain.

So after manually changing the url, I login as OpenEMR with my admin account, select the sample patient I created, then click “Authorize” on the final prompt. The tab then closes out and I am taken back to Swagger, where I am shown the following error:

I have no idea where to go from here and none of the resources I found online seem to help. Any help would be greatly appreciated!

Please let me know if there’s any more screenshots or information I need to provide.

Look at your Globals/Config->Connector-> Site Address Override is set. It needs to be set to http://localhost/openemr/ if that is where you have your webroot set.

Also in Globals → Logging->System Error Logging Options set it to be Debug. Check your php error logs for detailed logs of what may not be working for you.

Hi, can you please help me on this…

Demo Server Flow:

  1. https://one.openemr.io/c/openemr/oauth2/default/registration
  2. Swagger UI: OAuth2 Redirect
  3. OpenEMR Error
  4. https://one.openemr.io/c/openemr/oauth2/default/smart/patient-select
  5. https://one.openemr.io/c/openemr/oauth2/default/scope-authorize-confirm

My Local Windows Installation (7.0.2)
My Configuration:

  1. Created sample patient from UI
  2. Admin → Config → Connectors
    Site Address Override (if needed for OAuth2, FHIR, CCDA, or Payment Processing) = http://localhost/openemr

App Registration:

  1. From Postman: http://localhost/openemr/oauth2/default/registration
  2. Got client app registered and got client_id, client_secret
  3. Enabled my app from UI

My Authorization flow from Swagger:

  1. http://localhost/openemr/swagger/index.html
  2. Click on ‘Authorize’ and I can see below
    Authorization URL: /oauth2/default/authorize
    Token URL: /oauth2/default/token
    Flow: authorizationCode with PKCE
  3. Provided client_id, client_secret, select all scopes and click ‘Authorize’
  4. Opened a new tab in browser with http://localhost/oauth2/default/authorize?response_type=code&client_id=
    and the response is “The requested URL was not found on this server.”
  5. Updated the URL by adding /openemr after localhost as below
    http://localhost/openemr/oauth2/default/authorize?response_type=code&client_id=
  6. Now redirected to ‘Login Page’ (http://localhost/openemr/oauth2/default/provider/login)
  7. After entering the credentials, redirected to http://localhost/openemr/openemr/oauth2/default/smart/patient-select
    and the response is “The requested URL was not found on this server.”
  8. Updated the URL by removing one /openemr as http://localhost/openemr/oauth2/default/smart/patient-select
  9. Now patient selection is showed
  10. By selecting the patient, redirected to http://localhost/openemr/openemr/oauth2/default/smart/patient-select-confirm
    and the response is “The requested URL was not found on this server.”
  11. Again updated the URL by removing the extra /openemr and got the response as
    Warning: Undefined array key “csrf_token” in C:\xampp\htdocs\openemr\src\RestControllers\SMART\SMARTAuthorizationController.php on line 199
    Authentication Error

Though I followed the above suggestion by @adunsulag , it’s still not adding /openemr in initial request and adding extra /openemr for later requests. Not sure what’s happening. Can you please help me to fix this.

I noticed you are using local http. You’re going to have problems w/o SSL access as all of the cookies get blocked due to the Secure cookie flag.

There could be another bug with the way the /openemr/ sub-extension is being handled w/ swagger that’d need to be looked at. I thought it should be working, but would need to setup a test bed to verify.

So, are you suggesting that enabling SSL will resolve my issue since the cloud is functioning correctly with SSL enabled? Or should we address the Swagger handling issue you mentioned earlier first? We’re in a bit of a hurry to get this working from our local environment as we have some demos coming up. We would appreciate your help in resolving this issue since we can’t rely on the cloud servers due to their occasional downtime.

If you can set it up so that your installation is not in a subfolder you’ll have better results. I can confirm the URL re-routing is having problems with a sub-folder installation of ‘openemr’. now that I have a proper test bed up.

That said, you do need SSL enabled. There’s a pretty easy SSL setup using the docker images if you have any experience with that if you’re trying to demo.

If you drop the sub-folder from your Site Address Override, ie use http://localhost/ you won’t have the redirect problems from Postman that you were having.

It doesn’t fix it for swagger which still has issues with the /openemr/ prefix.

I opened a bug report for this here: bug: FHIR server URL is not handling webroot folders properly · Issue #8004 · openemr/openemr · GitHub

Feel free to add any additional comments you may have there.

I have installed it in the correct path as suggested by the installation document (not in subfolder).
C:\xampp\htdocs\openemr

I didn’t have experience working with docker and I didn’t have time to invest on it now. What do you suggest?

Where can I find the instructions to enable SSL?
If swagger is having the issues, what’s the other way to generate the tokens?
Can you please help me on where can I get the instructions to generate it.

Ok, new update from my side.

  1. Enabled SSL on my windows local installation
  2. Now the URL is https://localhost/openemr
  3. Set… Admin → Config → Connectors
    Site Address Override (if needed for OAuth2, FHIR, CCDA, or Payment Processing) = https://localhost
  4. Started using Postman instead of swagger to get the access token and finally got it
  5. Tried GET request for “https://localhost/openemr/apis/default/api/patient” in Postman and got the response as below…

There are other posts where people encountered this issue but no solution found in any of the posts. Any thoughts…?

On the first API request it attempts to generate the oapublic.key file in the path you see in the error. Its saying that for some reason it doesn’t have write access to that folder location or the key is not readable by PHP.

First step is to verify the key exists, 2nd verify that the apache process has read access to the file. I don’t typically work on windows so I can’t walk you through how you go about changing the file permissions on your directory or file but that’s where I’d start.

I can see the files in the expected location.

Permissions also looks good for both files.

I have recreated these files but still same error. By default it’s giving ‘too much permissions’ error. When I reduce the permissions for ‘Users’ Group, it says ‘the file doesn’t exist or can’t read’. Ufffff…loosing my mind on this.

This is the logic used for the key checking. Its a 3rd party php library.

       if (\strpos($keyPath, self::FILE_PREFIX) !== 0 && $this->isValidKey($keyPath, $this->passPhrase ?? '')) {
            $this->keyContents = $keyPath;
            $this->keyPath = '';
            // There's no file, so no need for permission check.
            $keyPermissionsCheck = false;
        } elseif (\is_file($keyPath)) {
            if (\strpos($keyPath, self::FILE_PREFIX) !== 0) {
                $keyPath = self::FILE_PREFIX . $keyPath;
            }

            if (!\is_readable($keyPath)) {
                throw new LogicException(\sprintf('Key path "%s" does not exist or is not readable', $keyPath));
            }
            $this->keyContents = \file_get_contents($keyPath);
            $this->keyPath = $keyPath;
            if (!$this->isValidKey($this->keyContents, $this->passPhrase ?? '')) {
                throw new LogicException('Unable to read key from file ' . $keyPath);
            }
        } else {
            throw new LogicException('Invalid key supplied');
        }

        if ($keyPermissionsCheck === true) {
            // Verify the permissions of the key
            $keyPathPerms = \decoct(\fileperms($this->keyPath) & 0777);
            if (\in_array($keyPathPerms, ['400', '440', '600', '640', '660'], true) === false) {
                \trigger_error(
                    \sprintf(
                        'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s',
                        $this->keyPath,
                        $keyPathPerms
                    ),
                    E_USER_NOTICE
                );
            }
        }
// ....
    private function isValidKey($contents, $passPhrase)
    {
        $pkey = \openssl_pkey_get_private($contents, $passPhrase) ?: \openssl_pkey_get_public($contents);
        if ($pkey === false) {
            return false;
        }
        $details = \openssl_pkey_get_details($pkey);

        return $details !== false && \in_array(
            $details['type'] ?? -1,
            [OPENSSL_KEYTYPE_RSA, OPENSSL_KEYTYPE_EC],
            true
        );
    }

The error you were getting suggests the key was not readable. You changed the permissions and that made it so the key was readable by apache/php.

Next its going to check to make sure the key is set to be a read-only permission, no writes at all. I don’t see where you are getting the “too much permissions” error. Are you seeing the “permissions are not correct, recommend changing to 600 or 660 instead of” error?

The guy who built this piece runs his system on windows so this all should be working. @sjpadgett what permissions does @vkoppuravuri need to set to mimic the unix permissions required?

I did find this issue on the league server recommending passing in the public CryptKey directly to bypass the issue on windows, but its from 2017 and again @sjpadgett I know you’ve tested this all working on windows, so I’m assuming you’ve already handled this.

Yes, this is the first error response in postman when I hit get patients API. After I removed the permissions for the ‘Users’ group on those two files, I started encountering a “file not available” error. I’m uncertain about which user group permissions need to be set and at what level. I noticed that the ‘Administrator’ user is running the Apache service and has ‘Full Control’ over these files, yet I’m still receiving the error indicating that the file is not accessible or cannot be read. Interestingly, when I open the file in Chrome, I can view the content without any issues. I’m puzzled as to why Apache is unable to read or access it.

You could try changing this line in the _rest_config.php:

to be the following

new CryptKey(self::self::$publicKey, null, false)

So the whole thing would look like this:

$server = new ResourceServer(
                new AccessTokenRepository(),
               new CryptKey(self::self::$publicKey, null, false)
            );

You’ll also need to make sure you have the read permissions set. IE use the Full Control piece where you are triggering the ‘permissions are not correct’ error and then passing in that 3rd parameter of false will bypass the permissions check.

This can get you moving forward until one of the windows users around here can tell you what the correct permisisons are.

What I find odd is you are getting this at the token verification. You should have had this error earlier in the process when you were doing the initial app registration as there’s another location in the AuthorizationController class that uses the same logic.

** Edited** to show name of file and remove quoted reply.

Okay, I did above changes but there are 2 corrections.

  1. Added “use League\OAuth2\Server\CryptKey;” in the imports section
  2. new CryptKey(self::self::$publicKey, null, false) is giving error so corrected as new CryptKey(self::$publicKey, null, false)

After that, I realised that my token got expired so generated new token using refresh token.

Now https://localhost/openemr/apis/default/api/patient API is giving below error.
Warning: foreach() argument must be of type array|object, null given in C:\xampp\htdocs\openemr\apis\dispatch.php on line 76

Fatal error: Uncaught TypeError: OpenEMR\Common\Http\HttpRestRequest::setAccessTokenScopes(): Argument #1 ($scopes) must be of type array, null given, called in C:\xampp\htdocs\openemr\apis\dispatch.php on line 83 and defined in C:\xampp\htdocs\openemr\src\Common\Http\HttpRestRequest.php:356 Stack trace: #0 C:\xampp\htdocs\openemr\apis\dispatch.php(83): OpenEMR\Common\Http\HttpRestRequest->setAccessTokenScopes(NULL) #1 {main} thrown in C:\xampp\htdocs\openemr\src\Common\Http\HttpRestRequest.php on line 356

Have you turned on the debug logs? Admin → Config → Logging->System Error Logging Options set it to be Debug.

I don’t know how you got null scopes, the debug log should tell what happened with your refresh token and regular token.

My apologies on the extra self::. Was some early morning coding.

Look in the logs to see what your access and refresh token scopes are being set to when you hit the endpoints.

This is what I can see from C:\xampp\apache\logs\error.log … (if this is the log file you are asking to look into)…

[Wed Feb 12 16:07:45.451819 2025] [php:notice] [pid 3384:tid 1912] [client ::1:50938] [2025-02-12T17:07:45.451755+01:00] OpenEMR.DEBUG: IdTokenSMARTResponse->getExtraParams() final params {“params”:{“id_token”:“eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJzWUMxdlVhTnQ3ZnR4WFVZeW1ZcWh6a1lhcm5CaFJtNWRmTklYQWRSNzFJIiwiaXNzIjoiaHR0cHM6Ly9sb2NhbGhvc3Qvb3BlbmVtci9vYXV0aDIvZGVmYXVsdCIsImlhdCI6MTczOTM3NjQ2NCwiZXhwIjoxNzM5MzgwMDYzLCJzdWIiOiI5ZTI2NGE2Mi1lNDE1LTQ2NjktOGM0OC1iNjMwNGY5YzM1ODkifQ.BRgRubjAAxAC8CU6mcYg4YzqlBFgSwLCPLuO3xwvbOYtY0sJlWT9XFwUomYC9aXg2kcp6KpmyiwabM0o9gvkmqfgLfgRIlnyBy-gdhOvo-KyZfRQPNKPmFxLNBYTAWMZCLeYeNJhbru8sTPx9Q3YAf4j5ejS5aC2Ti04vDg9JUUmf8UOpNu4xi-WI8uyg0N60C956ldRZ1HClPk__f1BKMm7Ayb3dJ7A0UZ-ttP64icTRy7B4pQeLdQ05miOdHMIUnQtekZspgWkEYRKCND0UHszhXYg81jyguEi26oRpVQbH_MLJXFWzfuAwNq1vuNk09uvNqZyUNzHhLdNU_TWHw”,“scope”:“openid offline_access patient/AllergyIntolerance.read patient/CareTeam.read patient/Condition.read patient/Encounter.read patient/Immunization.read patient/MedicationRequest.read patient/Observation.read patient/Patient.read patient/Procedure.read”}}
[Wed Feb 12 16:09:10.579050 2025] [php:warn] [pid 3384:tid 1908] [client ::1:50946] PHP Warning: foreach() argument must be of type array|object, null given in C:\xampp\htdocs\openemr\apis\dispatch.php on line 76
[Wed Feb 12 16:09:10.584053 2025] [php:error] [pid 3384:tid 1908] [client ::1:50946] PHP Fatal error: Uncaught TypeError: OpenEMR\Common\Http\HttpRestRequest::setAccessTokenScopes(): Argument #1 ($scopes) must be of type array, null given, called in C:\xampp\htdocs\openemr\apis\dispatch.php on line 83 and defined in C:\xampp\htdocs\openemr\src\Common\Http\HttpRestRequest.php:356\nStack trace:\n#0 C:\xampp\htdocs\openemr\apis\dispatch.php(83): OpenEMR\Common\Http\HttpRestRequest->setAccessTokenScopes(NULL)\n#1 {main}\n thrown in C:\xampp\htdocs\openemr\src\Common\Http\HttpRestRequest.php on line 356
[Wed Feb 12 16:09:44.941403 2025] [php:warn] [pid 3384:tid 1908] [client ::1:50950] PHP Warning: foreach() argument must be of type array|object, null given in C:\xampp\htdocs\openemr\apis\dispatch.php on line 76
[Wed Feb 12 16:09:44.941403 2025] [php:error] [pid 3384:tid 1908] [client ::1:50950] PHP Fatal error: Uncaught TypeError: OpenEMR\Common\Http\HttpRestRequest::setAccessTokenScopes(): Argument #1 ($scopes) must be of type array, null given, called in C:\xampp\htdocs\openemr\apis\dispatch.php on line 83 and defined in C:\xampp\htdocs\openemr\src\Common\Http\HttpRestRequest.php:356\nStack trace:\n#0 C:\xampp\htdocs\openemr\apis\dispatch.php(83): OpenEMR\Common\Http\HttpRestRequest->setAccessTokenScopes(NULL)\n#1 {main}\n thrown in C:\xampp\htdocs\openemr\src\Common\Http\HttpRestRequest.php on line 356

This is version 7.0.2 you are using right? Your logs are missing several log entries. Did you trim them for readability?

For example logs are missing from line 38:
$logger->debug(“dispatch.php requested”, [“resource” => $resource, “method” => $_SERVER[‘REQUEST_METHOD’]]);

And on line 75
$logger->debug(“Parsed oauth_scopes in AccessToken”, [“scopes” => $scopes]);

Also check your oauth_trusted_user table when you authorize a token and make sure your scopes are populated in the scopes column.

So strange as I can’t see how you are getting scopes in the IdTokenSMARTResponse but not getting them encoded in the Access Token.

You may need to update the CryptKey in the src/RestControllers/AuthorizationController.php like you did in the other file.

However, the whole thing should just have failed if it couldn’t encrypt the access token, so scratching my head on this.