cloudcreativity / laravel-json-api

JSON API (jsonapi.org) package for Laravel applications.
http://laravel-json-api.readthedocs.io/en/latest/
Apache License 2.0
780 stars 109 forks source link

Generating Passport bearer tokens #476

Closed dingo-d closed 4 years ago

dingo-d commented 4 years ago

I'm trying to create a session route in my API, that will create a Bearer token for a user that tries to enter their credentials. I have Laravel Passport set up and working. I also have OauthAccessToken model in my app, so I added

    'resources' => [
        'users' => User::class,
        'sessions' => OauthAccessToken::class,
    ],

to my json-api-v1.php config file and made a resource with php artisan make:json-api:resource sessions (and changed \App\Sessions to \App\OauthAccessToken classess in the Adapter).

Finally, I added in my api.php

JsonApi::register('v1')->routes(static function (Api $api) {
    $api->resource('session')->controller()->only('create');
});

I also added a SessionController with created(Request $request) method (where I'll add the token creation logic).

I tried to do a POST request from my Postman

POST /api/v1/session HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
    "data": {
        "type": "sessions",
        "attributes": {
            "username": "{{adminEmail}}",
            "password": "{{adminPass}}",
            "remember_me": "true"
        }   
    }
}

But I get

{
    "errors": [
        {
            "status": "409",
            "title": "Not Supported",
            "detail": "Resource type sessions is not supported by this endpoint.",
            "source": {
                "pointer": "/data/type"
            }
        }
    ]
}

What am I missing?

lindyhopchris commented 4 years ago

That'll be coming from the Validators class... what's in that?

lindyhopchris commented 4 years ago

Also, in your POST request you had POST /api/v1/session which should be POST /api/v1/sessions

dingo-d commented 4 years ago

Validators only have

    protected function rules($record = null): array
    {
        return [
            'email' => 'required|string|email',
            'password' => 'required|string',
            'remember_me' => 'boolean'
        ];
    }

Ok, so I changed to sessions, and I changed the api.php to

$api->resource('sessions')->controller('SessionController')->only('create'); // uses SessionController

And now I'm getting

{
    "errors": [
        {
            "status": "422",
            "title": "Unprocessable Entity",
            "detail": "The email field is required.",
            "source": {
                "pointer": "/data"
            }
        },
        {
            "status": "422",
            "title": "Unprocessable Entity",
            "detail": "The remember me field must be true or false.",
            "source": {
                "pointer": "/data/attributes/remember_me"
            }
        }
    ]
}

So this kinda did the trick I guess. I just need to see what's wrong with the email validation (remember me needs to be a boolean, and I passed a string).

Thanks!

EDIT:

I'm passing username, instead of email. My bad 🤦‍♂️

dingo-d commented 4 years ago

Ok, so I've fixed the request body

{
    "data": {
        "type": "sessions",
        "attributes": {
            "email": "{{adminEmail}}",
            "password": "{{adminPass}}",
            "remember_me": true
        }   
    }
}

and since I don't want the POST to actually write anything in my database, I've added a $guarded property to my App\JsonApi\V1\Sessions\Adapter class.

    protected $guarded = [
        'email',
        'password',
        'remember_me',
        'id',
        'user_id',
        'client_id',
        'name',
        'scopes',
        'revoked',
        'created_at',
        'updated_at',
        'expires_at',
    ];

But when I post I still get

local.ERROR: SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value (SQL: insert into `oauth_access_tokens` (`updated_at`, `created_at`) values (2020-01-29 09:45:13, 2020-01-29 09:45:13)) {"exception":"[object] (Illuminate\\Database\\QueryException(code: HY000): SQLSTATE[HY000]: General error: 1364 Field 'id' doesn't have a default value (SQL: insert into `oauth_access_tokens` (`updated_at`, `created_at`) values (2020-01-29 09:45:13, 2020-01-29 09:45:13)) at /Users/infinum-denis/Projects/Infinum/Tarisio/laravel-tarisio-api/vendor/laravel/framework/src/Illuminate/Database/Connection.php:669)

Is there a way to prevent filling anything out of the box, or do I need to write a custom adapter?

dingo-d commented 4 years ago

Ended up using custom controller for this functionality. Works fine - had to implement some middlewares and ensure that the responses are JSON:API compatible.

lindyhopchris commented 4 years ago

Glad you got it working.

If you had wanted to get it working via an adapter, you would have needed to use a non-Eloquent adapter: https://laravel-json-api.readthedocs.io/en/latest/basics/adapters/#custom-adapters

But if you've got it working, probably best to leave as is for the mo!