corbosman

corbosman

Technology Evangelist at XS4ALL

Member Since 5 Years Ago

Amsterdam

Experience Points
81,270
Total
Experience

3,730 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
789
Lessons
Completed
Best Reply Awards
12
Best Reply
Awards
  • start your engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-in-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • evangelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

Level 17
81,270 XP
May
06
3 weeks ago
Activity icon

Replied to Laravel Auth Routes

You don't really have access, it's just the browser cache.

May
05
3 weeks ago
Activity icon

Awarded Best Reply on Laravel Auth Routes

All you have to do is add the 'auth' middleware to all routes you want to protect by login. You can easily do that by creating a route group.

Route::middleware('auth')->group(function () {
  Route::get('/dashboard')..
  ...
});
Activity icon

Replied to Laravel Auth Routes

All you have to do is add the 'auth' middleware to all routes you want to protect by login. You can easily do that by creating a route group.

Route::middleware('auth')->group(function () {
  Route::get('/dashboard')..
  ...
});
Feb
21
3 months ago
Activity icon

Replied to Laravel Passport - Implicit Grant Not Working

Yeah but the implicit grant is still a user-initiated grant that normally goes through a user-authentication. So being sent to a login form is entirely expected. That sentence is so show the difference between an implicit grant and an authcode grant, both user based grants. The idea is that the user logs in with the authorisation server (passport), proving who they are and that that are ok with your app to get a token in their name.

Have a look at Taylor's new Laravel Airlock, maybe it's a better fit for you: https://laravel.com/docs/master/airlock

Feb
18
3 months ago
Activity icon

Replied to Laravel Passport - Implicit Grant Not Working

If you don't want a user to login, you should look at the client credentials grant

Feb
16
3 months ago
Activity icon

Replied to Laravel Passport - Implicit Grant Not Working

Did you enable implicit grant? If not, add this to your AuthServiceProvider

Passport::enableImplicitGrant();

You can find this in the docs

Jan
23
4 months ago
Activity icon

Replied to Passport - Omit Standard User Authentication And Use Custom Logic

You are absolutely right, I forgot to add that to the post. I had this in my code that I forgot to paste. Sorry about that.

        'my-provider' => [
            'driver' => 'my-provider',
            'model' => App\MyUser::class
        ],

With regards to having to do API calls to bigcommerce, in the past I did that by caching the requests in redis. You could surround the calls to bigcommerce in a cache()->remember(...) call. But I guess you could also use a session token. The thing is, the auth:api middleware needs to be able to convert an id that's encoded in the token into a user. As long as you can grab that user from someplace, some local table, cache, or from the api, doesnt matter. Whatever works for you.

Activity icon

Awarded Best Reply on Passport - Omit Standard User Authentication And Use Custom Logic

Hi, first of all, sorry, i was wrong. I hadn't used the password grant before and wasn't aware of how exactly it works. We only use the authcode and implicit grant. So, i spent some time to figure this out, and I think this works. Now bear with me, this is complicated.

First of al, it's important to know that the password grant gives you an option to verify the username and password. Check this section and this section. While reading through the code in passport, I noticed they also offer a single method to do both, which could be useful. You can find the relevant section in the code here.

With regards to the User Provider to use, I saw in the code that it used the provider set on the api guard. So, let's start.

First we need to configure config/auth.php. The important bit is to set the api.provider field to a custom user provider. A user provider is simply a class according to a standard interface that can return user objects based on credentials.


    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'my-provider',
        ],
    ],

We also need to make sure that laravel knows about this provider. You do that in AuthServiceProvider:

        app('auth')->provider('my-provider', function ($app, array $config) {
            return new MyUserProvider(new Client);
        });

This tells laravel that when you want to use my-provider, it needs to instantiate the MyUserProvider class, with Client as a parameter. I'm just providing the Client bit as an example that you can dependency inject whatever you want into MyUserProvider. In your case, maybe you want to inject Bigcommerce. You would do that here.

Let's check out this MyUserProvider.

<?php

namespace App\Auth;

use App\MyUser;
use Illuminate\Contracts\Auth\UserProvider;

class MyUserProvider implements UserProvider
{
    protected $client;

    public function __construct($client)
    {
        $this->client = $client;
    }

    public function retrieveById($identifier)
    {
        return new MyUser([
            'id' => 1,
            'username' => 'foo',
            'email'=> '[email protected]'
        ]);
    }

    public function retrieveByCredentials(array $credentials)
    {
        return new MyUser([
            'id' => 1,
            'username' => 'foo',
            'email'=> '[email protected]'
        ]);
    }

    public function retrieveByToken($identifier, $token) {}
    public function updateRememberToken($user, $token) {}
    public function validateCredentials($user, array $credentials) {}

}

So this class needs to implement a UserProvider contract. I think all you really need is RetrieveById, but im not 100% positive. Just add some logging to see which methods are being called. As you can see, this class returns a MyUser class. I am just hardcoding the fields, you would implement your API calls here and fetch the fields you'd need. You can have whatever fields you want, but I believe passport expects there to be an 'id' field. If you can't have an id field, let me know, I think there is a way around it.

This MyUser class looks like this.

<?php

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;

class MyUser extends Authenticatable
{
    use HasApiTokens;

    protected $fillable = [
        'id', 'username', 'email'
    ];


    public function findAndValidateForPassport($username, $password)
    {
        $attributes = [
            'id' => 1,
            'username' => 'foo',
            'email' => '[email protected]'
        ];

        return new static ($attributes);
    }

    public function findForPassport($username)
    {
        logger('finding for passport');
    }

    public function validateForPassportPasswordGrant($password)
    {
        logger('validateforpassport');
    }
}

The important part here is the 'HasApiTokens' trait. This adds a whole bunch of methods that passport uses. You also see I implemented the methods here that the docs tell you to use. Here you would add your code again that would fetch the user from your API, and then instantiates a new version of itself with those attributes. Since you now have this in 2 locations, maybe you can have some kind of class that does this for you. You would use that class here and in the UserProvider.

You may wonder why you need this in 2 places. This is because the password grant needs these findAndValidateForPassport() methods to implement your custom users. But the token guard, which protects your api routes, simply uses the api user provider to get the same data.

I think we now have all the required sections. If I now POST to /oath/token, I get back a token that's linked to user-id 1 (hardcoded). I see that in the database:

                                        id                                        | user_id | client_id | name |                         scopes                          | revoked |     created_at      |     updated_at      |     expires_at      
----------------------------------------------------------------------------------+---------+-----------+------+---------------------------------------------------------+---------+---------------------+---------------------+---------------------
 be100001d3286563cfeb7fb18f188b8d43fd816cf9f4080fe7f9eb836ea64236822aff13e87a1be1 |       1 |        30 |      | []                                                      | f       | 2020-01-21 13:46:25 | 2020-01-21 13:46:25 | 2020-01-22 13:46:25

Now I can add api routes protected by this token:

Route::middleware('auth:api')->get('/foo', function() {
    return 'bar';
});

And I tested this, if I call /api/foo, with the access token as a bearer token, i get 'bar'. How this works is, the auth:api middleware sees that you want to use MyProvider for api. Passport sees in the token that it's linked to user-id 1 (that's encoded in the token), here's the above token decoded:

{
  "aud": "30",
  "jti": "be100001d3286563cfeb7fb18f188b8d43fd816cf9f4080fe7f9eb836ea64236822aff13e87a1be1",
  "iat": 1579610785,
  "nbf": 1579610785,
  "exp": 1579697185,
  "sub": "1",
  "scopes": [],
}

It then asks your custom UserProvider if this user is valid, and if so, it finds the token in the database. If the token is valid, you get access.

I hope you could follow this. At least now I know how this part of passport works :)

Jan
22
4 months ago
Activity icon

Replied to Laravel Passport - Custom Authorization Question

You can redefine the routes in your RouteServiceProvider and attach middlewares. I do a similar thing with one of the oauth2 routes.

        Route::get('oauth/authorize', 'Laravel\Passport\Http\Controllers\[email protected]')->middleware(['web', 'auth', 'oauth-client-acl', 'modify-authcode-redirect']);
Jan
21
4 months ago
Activity icon

Replied to Passport - Omit Standard User Authentication And Use Custom Logic

Btw, you can probably create a MyUser that does not extend Authenticatable, but you'd have to figure out the details on which methods passport tries to call, and implement those yourself.

Activity icon

Replied to Passport - Omit Standard User Authentication And Use Custom Logic

Hi, first of all, sorry, i was wrong. I hadn't used the password grant before and wasn't aware of how exactly it works. We only use the authcode and implicit grant. So, i spent some time to figure this out, and I think this works. Now bear with me, this is complicated.

First of al, it's important to know that the password grant gives you an option to verify the username and password. Check this section and this section. While reading through the code in passport, I noticed they also offer a single method to do both, which could be useful. You can find the relevant section in the code here.

With regards to the User Provider to use, I saw in the code that it used the provider set on the api guard. So, let's start.

First we need to configure config/auth.php. The important bit is to set the api.provider field to a custom user provider. A user provider is simply a class according to a standard interface that can return user objects based on credentials.


    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'api' => [
            'driver' => 'passport',
            'provider' => 'my-provider',
        ],
    ],

We also need to make sure that laravel knows about this provider. You do that in AuthServiceProvider:

        app('auth')->provider('my-provider', function ($app, array $config) {
            return new MyUserProvider(new Client);
        });

This tells laravel that when you want to use my-provider, it needs to instantiate the MyUserProvider class, with Client as a parameter. I'm just providing the Client bit as an example that you can dependency inject whatever you want into MyUserProvider. In your case, maybe you want to inject Bigcommerce. You would do that here.

Let's check out this MyUserProvider.

<?php

namespace App\Auth;

use App\MyUser;
use Illuminate\Contracts\Auth\UserProvider;

class MyUserProvider implements UserProvider
{
    protected $client;

    public function __construct($client)
    {
        $this->client = $client;
    }

    public function retrieveById($identifier)
    {
        return new MyUser([
            'id' => 1,
            'username' => 'foo',
            'email'=> '[email protected]'
        ]);
    }

    public function retrieveByCredentials(array $credentials)
    {
        return new MyUser([
            'id' => 1,
            'username' => 'foo',
            'email'=> '[email protected]'
        ]);
    }

    public function retrieveByToken($identifier, $token) {}
    public function updateRememberToken($user, $token) {}
    public function validateCredentials($user, array $credentials) {}

}

So this class needs to implement a UserProvider contract. I think all you really need is RetrieveById, but im not 100% positive. Just add some logging to see which methods are being called. As you can see, this class returns a MyUser class. I am just hardcoding the fields, you would implement your API calls here and fetch the fields you'd need. You can have whatever fields you want, but I believe passport expects there to be an 'id' field. If you can't have an id field, let me know, I think there is a way around it.

This MyUser class looks like this.

<?php

namespace App;

use Laravel\Passport\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;

class MyUser extends Authenticatable
{
    use HasApiTokens;

    protected $fillable = [
        'id', 'username', 'email'
    ];


    public function findAndValidateForPassport($username, $password)
    {
        $attributes = [
            'id' => 1,
            'username' => 'foo',
            'email' => '[email protected]'
        ];

        return new static ($attributes);
    }

    public function findForPassport($username)
    {
        logger('finding for passport');
    }

    public function validateForPassportPasswordGrant($password)
    {
        logger('validateforpassport');
    }
}

The important part here is the 'HasApiTokens' trait. This adds a whole bunch of methods that passport uses. You also see I implemented the methods here that the docs tell you to use. Here you would add your code again that would fetch the user from your API, and then instantiates a new version of itself with those attributes. Since you now have this in 2 locations, maybe you can have some kind of class that does this for you. You would use that class here and in the UserProvider.

You may wonder why you need this in 2 places. This is because the password grant needs these findAndValidateForPassport() methods to implement your custom users. But the token guard, which protects your api routes, simply uses the api user provider to get the same data.

I think we now have all the required sections. If I now POST to /oath/token, I get back a token that's linked to user-id 1 (hardcoded). I see that in the database:

                                        id                                        | user_id | client_id | name |                         scopes                          | revoked |     created_at      |     updated_at      |     expires_at      
----------------------------------------------------------------------------------+---------+-----------+------+---------------------------------------------------------+---------+---------------------+---------------------+---------------------
 be100001d3286563cfeb7fb18f188b8d43fd816cf9f4080fe7f9eb836ea64236822aff13e87a1be1 |       1 |        30 |      | []                                                      | f       | 2020-01-21 13:46:25 | 2020-01-21 13:46:25 | 2020-01-22 13:46:25

Now I can add api routes protected by this token:

Route::middleware('auth:api')->get('/foo', function() {
    return 'bar';
});

And I tested this, if I call /api/foo, with the access token as a bearer token, i get 'bar'. How this works is, the auth:api middleware sees that you want to use MyProvider for api. Passport sees in the token that it's linked to user-id 1 (that's encoded in the token), here's the above token decoded:

{
  "aud": "30",
  "jti": "be100001d3286563cfeb7fb18f188b8d43fd816cf9f4080fe7f9eb836ea64236822aff13e87a1be1",
  "iat": 1579610785,
  "nbf": 1579610785,
  "exp": 1579697185,
  "sub": "1",
  "scopes": [],
}

It then asks your custom UserProvider if this user is valid, and if so, it finds the token in the database. If the token is valid, you get access.

I hope you could follow this. At least now I know how this part of passport works :)

Jan
20
4 months ago
Activity icon

Replied to Passport - Omit Standard User Authentication And Use Custom Logic

Hi, not sure what you mean with providers config. If you mean AuthServiceProvider, I have this.

        app('auth')->extend('xs4all-radius', function ($app, $name, array $config) {
            return new RadiusGuard($name, app('auth')->createUserProvider($config['provider']), $app->make('session.store'));
        });

        app('auth')->provider('portal', function ($app, array $config) {
            return new PortalDatabaseProvider($app->make($config['model']));
        });

The RadiusGuard just extends the SessionGuard.

<?php namespace App\Auth;

class RadiusGuard extends SessionGuard {

    /**
     * Attempt to authenticate a user using the given credentials.
     *
     * @param  array $credentials
     * @param  bool $remember
     * @param  bool $login
     * @return bool
     */
    public function attempt(array $credentials = [], $remember = false, $login = true)
    {
       // do your stuff here.
    }

}

My UserProvider is an implementation of Illuminate\Contracts\Auth\UserProvider. You have to make sure you implement all the methods, or at least provide stub methods so the interface is happy.

Jan
17
4 months ago
Activity icon

Replied to 401 Unauthorized When Creating Password Grant Tokens With Passport

Seems like your client id and/or client secret is not correct, since the error is "invalid_client".

Activity icon

Awarded Best Reply on Scale Laravel And Horizon (horizontally)

I believe this will work fine as long as they all use the same redis server.

Jan
14
4 months ago
Activity icon

Replied to Passport - Omit Standard User Authentication And Use Custom Logic

This is what I thought you meant. The api guard is meant to protect a resource endpoint that you want to protect with tokens. The oauth2 flow itself does not go through the api guard. Here is my auth.php config.

    'defaults' => [
        'guard' => 'portal',
        'passwords' => 'users',
    ],

   'guards' => [
        'api' => [
            'driver' => 'passport',
            'provider' => 'portal',
        ],

        'portal' => [
            'driver' => 'xs4all-radius',
            'provider' => 'portal'
        ]
    ],

So my default guard is 'portal', which uses the 'xs4all-radius' Guard driver for authentication, and a 'portal' UserProvider. These serve the oauth2 flow. When I want to protect api endpoints with the generated tokens that your clients get from passport, you protect them with the auth:api middleware. Like this:

Route::middleware('auth:api')->get('/user', ['as' => 'api.user', 'uses' => '[email protected]']);
Route::middleware('auth:api')->get('/groups', ['as' => 'api.groups', 'uses' => '[email protected]']);

Does that make sense in your situation?

Jan
13
4 months ago
Activity icon

Replied to Passport - Omit Standard User Authentication And Use Custom Logic

Maybe I misunderstood your question. Which oauth2 grant are you using? What exactly are you authenticating?

Jan
12
4 months ago
Activity icon

Replied to Passport - Omit Standard User Authentication And Use Custom Logic

Hi, this is definitely possible. We do the same except instead of an API we use a Radius server to authenticate users. What you need to do is write your own Auth Guard and perhaps User Provider. Then register those in config/auth.php

Activity icon

Replied to Laravel Password Hash

It's not strange at all. That's how password hashing works.

Theoretically, but I've never seen this done, you could generate some kind of hashing that includes the username I guess. If you really must. You could take the password and the username and hash them together.

A more common approach is to use some form of 2FA. That way, if the password is known for whatever reason, they still can't login without knowing a second key, often generated on the fly by some generator like Google Authenticator or Yubikeys. (we use both).

Jan
06
4 months ago
Activity icon

Replied to Scale Laravel And Horizon (horizontally)

I doubt it, but a clock skew is never a good thing. I would always run ntp services on my servers.

Activity icon

Replied to Scale Laravel And Horizon (horizontally)

I believe this will work fine as long as they all use the same redis server.

Jan
04
4 months ago
Activity icon

Replied to Execution Time Issues On Server. ( 150 Ms Average Localhost Vs 300 Ms Average On Live Server )

Does that table have a proper index? You can try to take the query from the debugbar and manually run it. You can then try to use the mysql EXPLAIN command to see if it uses the indices.

Activity icon

Replied to Pass Data From Controller To Blade, Then To Component

There's 2 problems with your code. First you need to make sure you use props on the vue component. Without props vue is not going to know you want to pass data to the component. Don't add 'besitzers' to your data object.

<script>
  export default {
    props: ['besitzers'],
        ...
  }
</script>

Second, if you're passing some data structure you should use :besitzers in your blade template. Note the colon there.

<vdt-search-base :besitzers='@json($besitzers)'></vdt-search-base>
Activity icon

Replied to Caching API GET Requests

One way would be to use Cache::remember. https://laravel.com/docs/6.x/cache#retrieving-items-from-the-cache , under "Retrieve and Store". It's a very convenient way to automatically cache your responses. Then use something like a redis cache server to speed up your calls.

Jan
03
4 months ago
Activity icon

Replied to Execution Time Issues On Server. ( 150 Ms Average Localhost Vs 300 Ms Average On Live Server )

Those response times are really high. If i add the above route to my current project using valet it takes about 15-20ms to respond. My first guess, do you have xdebug turned on? If so, turn it off and try again.