laravel / cashier-paddle

Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.
https://laravel.com/docs/cashier-paddle
MIT License
238 stars 57 forks source link

Paddle with Passport giving: Authentication header included, but incorrectly formatted #250

Closed jeanlinux closed 5 months ago

jeanlinux commented 5 months ago

Cashier Paddle Version

2.4

Laravel Version

11.0.1

PHP Version

8.1

Database Driver & Version

No response

Description

I am trying to setup cashier-paddle on laravel for my API service with passport for authentication, I have an endpoint /subscriptions that is supposed to return all subscriptions for the currently logged in user or guest if not logged in. but to I was getting curl ssl certificate error when I connect from localhost so I updated src/Cashier.php line 124

/* @var \Illuminate\Http\Client\Response $response / $response = Http::withToken($apiKey) ->withUserAgent('Laravel\Paddle/' . static::VERSION) ->withHeaders(['Paddle-Version' => 1]) ->$method("{$host}/{$uri}", $payload);

to

/* @var \Illuminate\Http\Client\Response $response / $response = Http::withToken($apiKey) ->withUserAgent('Laravel\Paddle/' . static::VERSION) ->withOptions(["verify" => false]) ->withHeaders(['Paddle-Version' => 1]) ->$method("{$host}/{$uri}", $payload);

When I make the request without bearer token (as guest) I get all the subscription plans for guests. But now I am getting another error when I make a get request with Bearer Authentication header.

Paddle API error 'Authentication header included, but incorrectly formatted' occurred

Here is my subscriptions controller.

<?php

namespace App\Http\Controllers;

use App\Models\Plan;
use Exception;
use Illuminate\Http\JsonResponse;
use Log;
use PDOException;

class SubscriptionsController extends Controller
{
    public function __construct()
    {
    }

    public function index(): JsonResponse
    {
        try {
            /**
             * This part assumes that the current billable instance is the authorised user.
             */
            if (!is_null(auth('api')->user())) {
                $billable = auth('api')->user();

                // Our list of available plans, note the name could be anything here for the plan model.
                $plans = Plan::whereIsAvailable(true)
                    ->get(['id', 'paddle_id', 'title', 'name', 'is_available']);

                Log::info('Plans are : ' . count($plans));

                $subscriptions = $plans->map(function ($plan) use ($billable) {

                    if ($currentSubscription = $billable->subscribed($plan->name)) {
                        /** For this example you can just giving them the option to cancel the plan*/
                        $payLink = $billable->subscription($plan->name)->cancelUrl();
                    } else {
                        $payLink = $billable->checkout($plan->name)
                            ->returnTo('https://pb2f0ybgfb.sharedwithexpose.com/dashboard');
                    }

                    return [
                        'title' => $plan->title,
                        'name' => $plan->name,
                        'payLink' => $payLink,
                        'current' => $currentSubscription,
                    ];
                });
            } else {
                // Our list of available plans, note the name could be anything here for the plan model.
                $plans = Plan::whereIsAvailable(true)
                    ->get(['id', 'paddle_id', 'title', 'name', 'is_available']);

                Log::info('guest Plans are : ' . count($plans));

                $subscriptions = $plans->map(function ($plan) {
                    return [
                        'title' => $plan->title,
                        'name' => $plan->name,
                    ];
                });
            }

            return new JsonResponse([
                'data' => $subscriptions,
            ], 200);
        } catch (PDOException $e) {
            Log::error($e->getMessage());

            return new JsonResponse(['error' => 'failed to list subscriptions'], 400);
        } catch (\Laravel\Paddle\Exceptions\PaddleException $e) {
            Log::error($e->getMessage());

            return new JsonResponse(['error' => 'could not list subscriptions'], 400);
        } catch (Exception $e) {
            Log::error($e->getMessage());

            return new JsonResponse(['error' => 'could not list subscriptions'], 400);
        }
    }

    public function billing(): JsonResponse
    {
        return new JsonResponse(['status' => 'billing goes here'], 200);
    }

    public function update_payment_method(): JsonResponse
    {
        $user = auth('api')->user();

        return new JsonResponse($user->subscription()->redirectToUpdatePaymentMethod());
    }
}

Here is my Plan model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Concerns\HasUuids;

class Plan extends Model
{
    use SoftDeletes, HasUuids;

    protected $fillable = [
        'paddle_id',
        'name',
        'title',
        'is_available',
    ];

    protected $visible = [
        'id',
        'paddle_id',
        'name',
        'title',
        'is_available',
    ];

    public function users()
    {
        return $this->HasMany(User::class);
    }
}

Steps To Reproduce

  1. Create plans on Paddle sandbox
  2. Seed database with your plans
  3. Install passport and configure
  4. Update laravel/cashier-paddle/src/Cashier.php to allow accessing paddle from localhost
  5. access subscription url without passport bearer token (You should see your subscriptions list)
  6. Now pass bearer token to the same route and see the result
driesvints commented 5 months ago

Hi there,

Thanks for reporting but it looks like this is a question which can be asked on a support channel. Please only use this issue tracker for reporting bugs with the library itself. If you have a question on how to use functionality provided by this repo you can try one of the following channels:

However, this issue will not be locked and everyone is still free to discuss solutions to your problem!

Thanks.

jeanlinux commented 5 months ago

Any suggestions, I am still struggling to get cashier-paddle and passport authentication to work, I need to get this behind me, I dont know why authorization header is being affected when I post authentication token to a route that will be calling cashier-paddle API.

Artemeey commented 3 months ago

The error "Authentication header included, but incorrectly formatted" may occur if you try php sdk with application SDK API key: https://vendors.paddle.com/sdk

Instead, you need to use authorization key: https://vendors.paddle.com/authentication