Conta
Conta

Reputation: 176

CORS Issues with Slim PHP API - "Http failure response: 0 Unknown Error"

I'm experiencing CORS-related issues when making requests to my Slim PHP API from my Angular application. I'm getting the following error message in the console:

Error from client log console: XHROPTIONS http://localhost:8080/api/validate CORS Missing Allow Credentials

Bloccata richiesta multiorigine (cross-origin): il criterio di corrispondenza dell’origine non consente la lettura della risorsa remota da http://localhost:8080/api/validate. Motivo: previsto “true” in header CORS “Access-Control-Allow-Credentials”.

Bloccata richiesta multiorigine (cross-origin): il criterio di corrispondenza dell’origine non consente la lettura della risorsa remota da http://localhost:8080/api/validate. Motivo: richiesta CORS non riuscita. Codice di stato: (null). Http failure response for http://localhost:8080/api/validate: 0 Unknown Error

Here is my middleware code:

php

  $fitnetApi->slim->add(function (Request $request, Response $response, callable $next) {
        $uri = $request->getUri()->getPath();
        
        // Controlla se l'URI inizia con '/api'
        if (strpos($uri, '/api') === 0) {
            $cookies = $request->getCookieParams();
            $token = $cookies['jwt_token'] ?? null; // Usa l'operatore null coalescing

    
            // Se non c'è un token, continua con il middleware successivo
            if (!$token) {
                return $response
                ->withHeader("Content-Type", "application/json")
                ->withStatus(401)
                ->write(json_encode([
                    "status" => "error",
                    "message" => "token invalid"
                ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
            }
    
            try {
                // Decodifica il token
                $decoded = JWT::decode($token, new Key('', 'HS256'));
    
                // Controlla se il token è scaduto
                if (isset($decoded->exp) && $decoded->exp < time()) {
                    
                    $rtoken = $cookies['rjwt_token'] ?? null;;
                    $decRjwt = JWT::decode($rtoken, new Key('', 'HS256'));
    
                    // Controlla se il rtoken esiste e non è scaduto
                    if ($decRjwt && isset($decRjwt->exp) && $decRjwt->exp > time()) {
                        // Rigenera un token
                        $newToken = JWT::encode(
                            [
                                'id' => $decoded->id,
                                'type' => $decoded->type,
                                'exp' => time() + 60 * 15 // 15 minuti
                            ],
                            "",
                            "HS256"
                        );
    
                        // Aggiunge il nuovo token come attributo alla richiesta
                        $request = $request->withAttribute('new_token', $newToken);
                    } else {
                        // Se il rtoken è scaduto, restituisci un errore
                        return $response
                            ->withHeader("Content-Type", "application/json")
                            ->withStatus(401)
                            ->write(json_encode([
                                "status" => "error",
                                "message" => "rtoken expired, renew auth"
                            ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
                    }
                }
            } catch (ExpiredException $e) {
                // Gestisci il caso in cui il token JWT è scaduto
                return $response
                    ->withHeader("Content-Type", "application/json")
                    ->withStatus(401)
                    ->write(json_encode([
                        "status" => "error",
                        "message" => "Token expired"
                    ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
            } catch (SignatureInvalidException $e) {
                // Gestisci il caso in cui il token JWT è invalido
                return $response
                    ->withHeader("Content-Type", "application/json")
                    ->withStatus(401)
                    ->write(json_encode([
                        "status" => "error",
                        "message" => "Invalid token signature"
                    ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
            } catch (\Exception $e) {
                // Gestione generica di eccezioni JWT
                return $response
                    ->withHeader("Content-Type", "application/json")
                    ->withStatus(401)
                    ->write(json_encode([
                        "status" => "error",
                        "message" => "Invalid token"
                    ], JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
            }
        }
    
        // Continua con il prossimo middleware o la route
        return $next($request, $response);
    });

cors settings in middleware:

 $fitnetApi->slim->add(new Tuupola\Middleware\CorsMiddleware([
        "origin" => ["http://localhost:8100"],
        "methods" => ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
        "headers.allow" => ["Token", "Authorization", "If-Match", "If-Unmodified-Since", "Content-Type"],
        "headers.expose" => ["Authorization"],
        "credentials" => true,
        "cache" => 0,
    ]));

The error occurs when making a POST request to http://localhost:8080/api/validate. Despite the CORS headers being set, I still receive an "Unknown Error" with a status of 0.

I've verified that the backend is running on localhost:8080. The API responds correctly to requests made through Postman. I've checked for JavaScript errors in the Angular application.

What could be causing these CORS issues, and how can I fix the error so that my Angular application can communicate with the Slim PHP API successfully?

Any help would be appreciated!

Upvotes: 3

Views: 174

Answers (3)

iammursal
iammursal

Reputation: 26

I've never used Slim, but I think the header(Access-Control-Allow-Origin) is probably getting overridden with a diff port in the middleware later in the code that you have shared(see line 43). Also you seems to have missed one line that I've added below.

So the closure code should probably start something like this:

$fitnetApi->slim->add(function (Request $request, Response $response, callable $next) {
        $uri = $request->getUri()->getPath();
        $res = $next($req, $res); // you forgot this line
        // Imposta gli header CORS
        $res = $res
            ->withHeader('Access-Control-Allow-Origin', 'http://localhost:8100') // Cambia con l'URL del frontend
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
            ->withHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type')
            ->withHeader('Access-Control-Allow-Credentials', 'true');

    // Gestisci le richieste OPTIONS
    if ($request->getMethod() === 'OPTIONS') {
        return $response;
    }

    // Prosegui solo se l'URI inizia con '/api'
    if (strpos($uri, '/api') === 0) {
        $cookies = $request->getCookieParams();
        $token = $cookies['jwt_token'] ?? null;

If that did not work, try this

$res = $res->withHeader('Access-Control-Allow-Origin', '*'); 

Upvotes: 0

Bogghi
Bogghi

Reputation: 45

I'd like to point out that in your Tuupola\Middleware\CorsMiddleware instance you indicated as origin http://localhost:8100 but your are on port 8080 so that could be a starting point.

if this doesn't work I suggest lazy CORS handling, as indicated in slim doc, here's an example:

    return $response
            ->withHeader('Access-Control-Allow-Origin', 'http://localhost:8080')
            ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
            ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');

Upvotes: 0

Arun P
Arun P

Reputation: 893

you need to handle OPTIONS Requests in Slim by adding the handler seperately

$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});

Refer : https://www.slimframework.com/docs/v3/cookbook/enable-cors.html

you can also try adding CORS header directly in Apache , try adding this to .htaccess

<IfModule mod_headers.c>
    Header always set Access-Control-Allow-Origin "http://localhost:8100"
    Header always set Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS"
    Header always set Access-Control-Allow-Headers "Token, Authorization, If-Match, If-Unmodified-Since, Content-Type"
    Header always set Access-Control-Allow-Credentials "true"
</IfModule>

Upvotes: 3

Related Questions