Integrate Firebase Authentication with Slim

Hi all, I am working on a new project which use Firebase and would I would like to integrate it with my Slim REST API. I cloned a Slim 4 skeleton add it my code in the middleware then when I make my calls with X-Authorization Bearer but get the following error:

slim.WARNING: OpenSSL error: error:0906D06C:PEM routines:PEM_read_bio:no start line [“eyJhbGciOiJSUzI1NiIsIm…”]

“description”: "ERROR: openssl_verify(): supplied key param cannot be coerced into a public key on line 243 in file.

Any ideas what might be wrong? the secret and token used are checked in a simple php file and are valid.

This is my middleware.php

<?php

declare(strict_types=1);

use Psr\Http\Message\ServerRequestInterface as Request;

use Psr\Http\Server\RequestHandlerInterface as RequestHandler;

use Slim\Psr7\Response;

use App\Application\Middleware\SessionMiddleware;

use App\Application\Middleware\CorsMiddleware;

use Slim\App;

//Extra for auth

use Tuupola\Middleware\HttpBasicAuthentication;

use \Firebase\JWT\JWT;

use Monolog\Logger;

use Monolog\Handler\RotatingFileHandler;

return function (App $app) {

    $app->add(CorsMiddleware::class);

    $container = $app->getContainer();

    

    $rawPublicKeys = file_get_contents('https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com');

    $keys = json_decode($rawPublicKeys, true);

    $keyKidsArray= array_keys($keys);

    $pKeysArray = array_values($keys);

    $secrets = $keyKidsArray[0] . ':' . $pKeysArray[0] . ',' . $keyKidsArray[1] . ':' . $pKeysArray[1];

    $logger = new Logger("slim");

    $rotating = new RotatingFileHandler(__DIR__ . "/logs/slim.log", 0, Logger::DEBUG);

    $logger->pushHandler($rotating);

    echo $secrets;

    

    $app->add(new Tuupola\Middleware\JwtAuthentication([

        "ignore" => ["/api/records/countries","/faqs"],

        "algorithm" => ["RS256"],

        "header" => "X-Authorization",

        "regexp" => "/Bearer\s+(.*)$/i",

        "logger" => $logger,

        "secret" => $secrets,

        "secure" => false,

        "error" => function ($response, $arguments) {

            $data["status"] = "error";

            $data["message"] = $arguments["message"];

            return $response

                ->withHeader("Content-Type", "application/json")

                ->getBody()->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));

        }

        

    ]));

    

};

Hi @leossmith

What are you trying to achieve by downloading the public keys for each API request from the Google server?

According to Tuupola’s documentation, the secret is just a fixed string.

For simplicity’s sake examples show secret hardcoded in code. In real life you should store it somewhere else. Good option is environment variable. You can use dotenv or something similar for development. Examples assume you are using Slim Framework.

$app->add(new \Tuupola\Middleware\JwtAuthentication([
    "secret" => "supersecretkeyyoushouldnotcommittogithub"
]));

slim.WARNING: OpenSSL error: error:0906D06C:PEM routines:PEM_read_bio:no start line

AFAIK, the Tuupola JwtAuthentication doesn’t use OpenSSL or anyting similar.

Hi Odan,

using the secrets from Google server for firebase, you can use the firebase authentication generated JWT and validate it in your server. So the user flow is: Users login with firebase, gets token, make a request to my slim api (get pois with X-Authorization Bearer TOKEN_FROM_FIREBASE), midleware checks token against keys and authorizes user in my API.

Although I have managed to get it working with other systems (check for example this ), it looks like the issue here is Firebase/php-jwt, which is used by Tuupola JwtAuthentication and not processing the keys as should.

I think, in your special use case, Tuupola\JwtAuthentication is not the right “tool” you are looking for because it doesn’t support public keys etc.

Can you suggest another lib or even another way to approach this?

EDIT:
Working further with it, i am now 100% that Tuupola\JwtAuthentication is not the issue. Editing line 243 in Firebase/php-jwt/JWT.php (//$success = openssl_verify($msg, $signature, $key, $algorithm); ) allows the system to authenticate correctly and get the expected behavior.

Ok so after further work with it, it looks like the firebase/php-jwt does all the job of splitting the keys to KID, secret etc internally and I didnt have to provide them on my own. After passing the $keys as a secret for the middleware, everything worked as should.

@leossmith did you get how to make this work? I’m in the same case of yours and don’t know how to make this work.

@gregorispielmann Yes I made it work. This is my midleware:

return function (App $app) {
$app->add(CorsMiddleware::class);

$container = $app->getContainer();

$rawPublicKeys = file_get_contents('https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com');
$keys = json_decode($rawPublicKeys, true);

$logger = new Logger("slim");
$rotating = new RotatingFileHandler(__DIR__ . "/logs/slim.log", 0, Logger::DEBUG);
$logger->pushHandler($rotating);

$app->add(new Tuupola\Middleware\JwtAuthentication([
    "ignore" => ["/api/records/countries","/faqs"],
    "algorithm" => ["RS256"],
    "header" => "X-Authorization",
    "regexp" => "/Bearer\s+(.*)$/i",
    "logger" => $logger,
    "secret" => $keys,
    "secure" => false,
    "error" => function ($response, $arguments) {
        $data["status"] = "error";
        $data["message"] = $arguments["message"];
        return $response
            ->withHeader("Content-Type", "application/json")
            ->getBody()->write(json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
    }
]));

};

@leossmith thank you! You’ve helped me a lot at github too.

Thanks again!

Happy to help :slight_smile: This might be a good thing to add in documentation as it looks both Firebase Auth and Auth0 are used a lot these days.