php-crud-api: Google Firebase JWT authorization to CRUD API fails

I tried following the instructions in the README.md to use authorization with JWT on the php-crud-api, but I must be doing something incorrectly, as all my requests are returning a 403 status with a 1012 error code.

My mobile (Android) app created with Ionic framework uses Google Firebase for signing up and logging in new users. Authorization is handled by Firebase, where I have successfully created a project and completed the integration with my app. New users are able to sign up via email and log in to the app.

Via the AngularFireAuth library 'angularfire2/auth' , I can retrieve a token for the signed-in user account.

getToken() { return this.afAuth.auth.currentUser.getIdToken(); }

In the php-file, I have following configuration:

    $config = new Config([
        'username' => 'username_for_database',
        'password' => 'password',
        'database' => 'xx_database',
        'address' => 'mysqlxx5.domain.xx',
        'cacheType' => 'NoCache',
        'middlewares' => 'authorization, jwtAuth',
        'jwtAuth.secret' => '-----BEGIN CERTIFICATE-----\nMII**secret-stuff-here--2C\n-----END CERTIFICATE-----\n'
    ]);

I got the ‘jwtAuth.secret’ from the link in the documentation:

https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com](https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com)

What is unclear to me though, is how the service account is linked to the user’s token?

These are the service accounts currently defined in my project. The last one in the list was created for the API access.

service

How can start making successful API requests via the retrieved user token? Or do I need to handle this differently?

Many thanks!

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 1
  • Comments: 35 (28 by maintainers)

Most upvoted comments

I have been using the above method for 2 years now without any issues, so it should be ok to use.

Happy New Year! I created a PR with some additions to the README.md. Please see https://github.com/mevdschee/php-crud-api/pull/607

I got it working 😃 It seems important to use double quotes in the secrets string definition. Also, the string may not contain any spaces before or after the ‘:’ sign in the string. This is what my public key looks like in the config:

'jwtAuth.secrets' => "ce5ced6e40dcd1eff407048867b1ed1e706686a0:-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIExun9bJSK1wwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkx\nMjIyMjEyMTA3WhcNMjAwMTA4MDkzNjA3WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKsvVDUwXeYQtySNvyI1/tZAk0sj7Zx4/1+YLUomwlK6vmEd\nyl2IXOYOj3VR7FBA24A9//nnrp+mV8YOYEOdaWX7PQo0PIPFPqdA0r7CqBUWHPfQ\n1WVHVRQY3G0c7upM97UfMes9xOrMqyvecMRk1e5S6eT12Zh2og7yiVs8gP83M1EB\nGqseUaltaadjyT35w5B0Ny0/7NdLYiv2G6Z0S821SxvSo1/wfmilnBBKYYluP0PA\n9NPznWFP6uXnX7gKxyJT9//cYVxTO6+b1TT13Yvrpm1a4EuCOhLrZH6ErHQTccAM\nhAx8mdNtbROsp0dlPKrSfqO82uFz45RXZYmSeP0CAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBACNsJ5m00gdTvD6j6ahURsGrNZ0VJ0YREVQ5U2Jtubr8\nn2fuhMxkB8147ISzfi6wZR+yNwPGjlr8JkAHAC0i+Nam9SqRyfZLqsm+tHdgFT8h\npa+R/FoGrrLzxJNRiv0Trip8hZjgz3PClz6KxBQzqL+rfGV2MbwTXuBoEvLU1mYA\no3/UboJT7cNGjZ8nHXeoKMsec1/H55lUdconbTm5iMU1sTDf+3StGYzTwC+H6yc2\nY3zIq3/cQUCrETkALrqzyCnLjRrLYZu36ITOaKUbtmZhwrP99i2f+H4Ab2i8jeMu\nk61HD29mROYjl95Mko2BxL+76To7+pmn73U9auT+xfA=\n-----END CERTIFICATE-----\n",

Hey @leossmith , does getting the public keys every time poses some issue? The public key refreshes very often so the jwt becomes invalid every minute

Yes, I keep on getting this error now:

PHP Warning: openssl_verify(): supplied key param cannot be coerced into a public key

I wonder if there still is something wrong with the public key formatting? 'jwtAuth.secrets' => 'ce5ced6e40dcd1eff407048867b1ed1e706686a0:-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIExun9bJSK1wwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkx\nMjIyMjEyMTA3WhcNMjAwMTA4MDkzNjA3WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKsvVDUwXeYQtySNvyI1/tZAk0sj7Zx4/1+YLUomwlK6vmEd\nyl2IXOYOj3VR7FBA24A9//nnrp+mV8YOYEOdaWX7PQo0PIPFPqdA0r7CqBUWHPfQ\n1WVHVRQY3G0c7upM97UfMes9xOrMqyvecMRk1e5S6eT12Zh2og7yiVs8gP83M1EB\nGqseUaltaadjyT35w5B0Ny0/7NdLYiv2G6Z0S821SxvSo1/wfmilnBBKYYluP0PA\n9NPznWFP6uXnX7gKxyJT9//cYVxTO6+b1TT13Yvrpm1a4EuCOhLrZH6ErHQTccAM\nhAx8mdNtbROsp0dlPKrSfqO82uFz45RXZYmSeP0CAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBACNsJ5m00gdTvD6j6ahURsGrNZ0VJ0YREVQ5U2Jtubr8\nn2fuhMxkB8147ISzfi6wZR+yNwPGjlr8JkAHAC0i+Nam9SqRyfZLqsm+tHdgFT8h\npa+R/FoGrrLzxJNRiv0Trip8hZjgz3PClz6KxBQzqL+rfGV2MbwTXuBoEvLU1mYA\no3/UboJT7cNGjZ8nHXeoKMsec1/H55lUdconbTm5iMU1sTDf+3StGYzTwC+H6yc2\nY3zIq3/cQUCrETkALrqzyCnLjRrLYZu36ITOaKUbtmZhwrP99i2f+H4Ab2i8jeMu\nk61HD29mROYjl95Mko2BxL+76To7+pmn73U9auT+xfA=\n-----END CERTIFICATE-----\n'

Had another issue in my UI code, occasionally the token would be sent as undefined. After resolving this, the code ends up on the back-end, so I did some more logging and here are the print-outs:

[30-Dec-2019 13:28:24 Europe/Helsinki] X-Authorization
[30-Dec-2019 13:28:24 Europe/Helsinki] header value:
[30-Dec-2019 13:28:24 Europe/Helsinki] Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImN********************REMOVED
[30-Dec-2019 13:28:24 Europe/Helsinki] Bearer
[30-Dec-2019 13:28:24 Europe/Helsinki] eyJhbGciOiJSUzI1NiIsImtpZCI6ImN********************REMOVED
[30-Dec-2019 13:28:24 Europe/Helsinki] getClaims()
[30-Dec-2019 13:28:24 Europe/Helsinki] getVerifiedClaims()
[30-Dec-2019 13:28:24 Europe/Helsinki] Public key:
[30-Dec-2019 13:28:24 Europe/Helsinki] -----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIExun9bJSK1wwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkx\nMjIyMjEyMTA3WhcNMjAwMTA4MDkzNjA3WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKsvVDUwXeYQtySNvyI1/tZAk0sj7Zx4/1+YLUomwlK6vmEd\nyl2IXOYOj3VR7FBA24A9//nnrp+mV8YOYEOdaWX7PQo0PIPFPqdA0r7CqBUWHPfQ\n1WVHVRQY3G0c7upM97UfMes9xOrMqyvecMRk1e5S6eT12Zh2og7yiVs8gP83M1EB\nGqseUaltaadjyT35w5B0Ny0/7NdLYiv2G6Z0S821SxvSo1/wfmilnBBKYYluP0PA\n9NPznWFP6uXnX7gKxyJT9//cYVxTO6+b1TT13Yvrpm1a4EuCOhLrZH6ErHQTccAM\nhAx8mdNtbROsp0dlPKrSfqO82uFz45RXZYmSeP0CAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBACNsJ5m00gdTvD6j6ahURsGrNZ0VJ0YREVQ5U2Jtubr8\nn2fuhMxkB8147ISzfi6wZR+yNwPGjlr8JkAHAC0i+Nam9SqRyfZLqsm+tHdgFT8h\npa+R/FoGrrLzxJNRiv0Trip8hZjgz3PClz6KxBQzqL+rfGV2MbwTXuBoEvLU1mYA\no3/UboJT7cNGjZ8nHXeoKMsec1/H55lUdconbTm5iMU1sTDf+3StGYzTwC+H6yc2\nY3zIq3/cQUCrETkALrqzyCnLjRrLYZu36ITOaKUbtmZhwrP99i2f+H4Ab2i8jeMu\nk61HD29mROYjl95Mko2BxL+76To7+pmn73U9auT+xfA=\n-----END CERTIFICATE-----\n
[30-Dec-2019 13:28:24 Europe/Helsinki] PHP Warning:  openssl_verify(): supplied key param cannot be coerced into a public key in /*****/*******/public_html/********/api/api.php on line 7664
[30-Dec-2019 13:28:24 Europe/Helsinki] Claims is empty!

First part of the problem found… Somewhere along the editing, I must have accidently deleted this line from theprocess()method (ooops):

$token = $this->getAuthorizationToken($request);

Adding it back in already takes me much further… So the next issue:

        private function getAuthorizationToken(ServerRequestInterface $request): string
        {
            $headerName = $this->getProperty('header', 'X-Authorization');
            $headerValue = RequestUtils::getHeader($request, $headerName);
            $parts = explode(' ', trim($headerValue), 2);
            if (count($parts) != 2) {
                return '';
            }
            if ($parts[0] != 'Bearer') {
                return '';
            }
            return $parts[1];
        }

The token part is returned as undefined.

No, it is not 😦 No header, no value. The function/method is not even called…

It seems that none of the private functions inside class JwtAuthMiddleware are reached. Only the public function process() is gone through, and there it fails with the authentication error.

Btw, thanks for your effort and quick replies, I appreciate the help!

I am more of a front-end person… 😃 How can I trace whether the php.api is reading the token? What is the best place to add e.g. some ‘error_logs()’ statements to read the info that is being passed on inside the php?

It seems that the token is not found, as inside this function the claims are empty:

        public function process(ServerRequestInterface $request, RequestHandlerInterface $next): ResponseInterface
        {
            if (session_status() == PHP_SESSION_NONE) {
                if (!headers_sent()) {
                    session_start();
                }
            }
            if ($token) {
                $claims = $this->getClaims($token);
                $_SESSION['claims'] = $claims;
                if (empty($claims)) {
                    error_log('Claims is empty!');
                    return $this->responder->error(ErrorCode::AUTHENTICATION_FAILED, 'JWT');
                }
                if (!headers_sent()) {
                    session_regenerate_id();
                }
            }
            if (empty($_SESSION['claims'])) {
                $authenticationMode = $this->getProperty('mode', 'required');
                if ($authenticationMode == 'required') {
                    return $this->responder->error(ErrorCode::AUTHENTICATION_REQUIRED, '');
                }
            }
            return $next->handle($request);
        }

I double-checked my front-end code, and it correctly retrieves the token from the logged in user. The token is then passed on in the ‘X-Authorization’ header of the request, which contains the string as e.g. Bearer eyJhb....etc....

Somehow the token is not properly detected via PHP, but I seem to lack the skills to properly pinpoint the problem on that end 😕

    $config = new Config([
        'username' => 'xxxxxxxx',
        'password' => 'xxxxxxxx',
        'database' => 'xxxxxxxx',
        'address' => 'mysql05.xxxxxx.xxx',
        'cacheType' => 'NoCache',
        'middlewares' => 'cors, jwtAuth, authorization',
        'jwtAuth.secrets' => 'ce5ced6e40dcd1eff407048867b1ed1e706686a0:-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIExun9bJSK1wwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkx\nMjIyMjEyMTA3WhcNMjAwMTA4MDkzNjA3WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKsvVDUwXeYQtySNvyI1/tZAk0sj7Zx4/1+YLUomwlK6vmEd\nyl2IXOYOj3VR7FBA24A9//nnrp+mV8YOYEOdaWX7PQo0PIPFPqdA0r7CqBUWHPfQ\n1WVHVRQY3G0c7upM97UfMes9xOrMqyvecMRk1e5S6eT12Zh2og7yiVs8gP83M1EB\nGqseUaltaadjyT35w5B0Ny0/7NdLYiv2G6Z0S821SxvSo1/wfmilnBBKYYluP0PA\n9NPznWFP6uXnX7gKxyJT9//cYVxTO6+b1TT13Yvrpm1a4EuCOhLrZH6ErHQTccAM\nhAx8mdNtbROsp0dlPKrSfqO82uFz45RXZYmSeP0CAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBACNsJ5m00gdTvD6j6ahURsGrNZ0VJ0YREVQ5U2Jtubr8\nn2fuhMxkB8147ISzfi6wZR+yNwPGjlr8JkAHAC0i+Nam9SqRyfZLqsm+tHdgFT8h\npa+R/FoGrrLzxJNRiv0Trip8hZjgz3PClz6KxBQzqL+rfGV2MbwTXuBoEvLU1mYA\no3/UboJT7cNGjZ8nHXeoKMsec1/H55lUdconbTm5iMU1sTDf+3StGYzTwC+H6yc2\nY3zIq3/cQUCrETkALrqzyCnLjRrLYZu36ITOaKUbtmZhwrP99i2f+H4Ab2i8jeMu\nk61HD29mROYjl95Mko2BxL+76To7+pmn73U9auT+xfA=\n-----END CERTIFICATE-----\n',
        'cors.allowedOrigins' => '*',
        'cors.allowHeaders' => 'X-Authorization'
    ]);

Still no luck 😦 I tried several combinations with string formats, but all of them return the same 403 / 1012 error.

Also, I checked that I had the correct “kid” from the public certificate , matching with the decoded token:

jwt

I wish it was that simple, but that didn’t help. Any other ideas?