Asked  7 Months ago    Answers:  5   Viewed   36 times

I'm using Laravel Framework version 5.3.9, fresh download nothing added on via composer(except "laravel/passport": "^1.0").

I did all the things suggested in the docs. Tables are created, routes are up, everything works fine. However I need passport for an API.

My routes look like so:

+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
| Domain | Method   | URI                                     | Name                 | Action                                                                     | Middleware |
+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+
|        | GET|HEAD | /                                       |                      | Closure                                                                    | web        |
|        | GET|HEAD | api/v1/users/register                   | api::users::register | AppHttpControllersApiV1SocialController@register                      | api,auth   |
|        | POST     | oauth/authorize                         |                      | LaravelPassportHttpControllersApproveAuthorizationController@approve  | web,auth   |
|        | GET|HEAD | oauth/authorize                         |                      | LaravelPassportHttpControllersAuthorizationController@authorize       | web,auth   |
|        | DELETE   | oauth/authorize                         |                      | LaravelPassportHttpControllersDenyAuthorizationController@deny        | web,auth   |
|        | GET|HEAD | oauth/clients                           |                      | LaravelPassportHttpControllersClientController@forUser                | web,auth   |
|        | POST     | oauth/clients                           |                      | LaravelPassportHttpControllersClientController@store                  | web,auth   |
|        | PUT      | oauth/clients/{client_id}               |                      | LaravelPassportHttpControllersClientController@update                 | web,auth   |
|        | DELETE   | oauth/clients/{client_id}               |                      | LaravelPassportHttpControllersClientController@destroy                | web,auth   |
|        | GET|HEAD | oauth/personal-access-tokens            |                      | LaravelPassportHttpControllersPersonalAccessTokenController@forUser   | web,auth   |
|        | POST     | oauth/personal-access-tokens            |                      | LaravelPassportHttpControllersPersonalAccessTokenController@store     | web,auth   |
|        | DELETE   | oauth/personal-access-tokens/{token_id} |                      | LaravelPassportHttpControllersPersonalAccessTokenController@destroy   | web,auth   |
|        | GET|HEAD | oauth/scopes                            |                      | LaravelPassportHttpControllersScopeController@all                     | web,auth   |
|        | POST     | oauth/token                             |                      | LaravelPassportHttpControllersAccessTokenController@issueToken        |            |
|        | POST     | oauth/token/refresh                     |                      | LaravelPassportHttpControllersTransientTokenController@refresh        | web,auth   |
|        | GET|HEAD | oauth/tokens                            |                      | LaravelPassportHttpControllersAuthorizedAccessTokenController@forUser | web,auth   |
|        | DELETE   | oauth/tokens/{token_id}                 |                      | LaravelPassportHttpControllersAuthorizedAccessTokenController@destroy | web,auth   |
+--------+----------+-----------------------------------------+----------------------+----------------------------------------------------------------------------+------------+

All the web routes are there, there are no api related routes, since Passport doesn't provide anything of that sort out of the box.

The API itself is intended to be used by a trusted client, it's made for a mobile application that does require a login however, said login will bypass a few steps.

Once a user access the /register route, the registration process itself is quite simple: access the user's facebook account an grab a few fields - email, facebook id, name an profile picture and from that point onwards the users is considered registered. But the user will NOT login with facebook(this is a very important aspect). The consumer app will be issued a token and use that token to access various endpoints of the api(that require a token to use).

So it boils down to this. I need to issue an access token to the consumer app that access the API. The API itself will only have one client, that is the mobile app itself. Users that use the app are not considered clients of the API but clients of the mobile app itself.

So far Passport is a headache to work with when it comes to implementing API related stuff, either that or I can't figure out how to make it work properly.

I've created a test client in the oauth_clients table that looks like so:

enter image description here

I'm using Postman to access api/v1/users/register route that has the auth middleware with the following JSON application/json

{
    "grant_type" : "authorization_code",
    "client_id" : 5,
    "client_secet": "y5dvPIOxQJOjYn7w2zzg4c6TRrphsrNFWbG4gAUL"
}

Which of course will result in a

{"error":"Unauthenticated."}

It makes perfect sense. Out of pure curiosity I changed the /register route to this:

Route::group([
    'middleware' => [
    ],
], function ()
{
    Route::group([
        'prefix' => 'users',
        'as'     => 'users::',
    ], function ()
    {
//        Route::get('/register', ['as'   => 'register', 'uses' => 'ApiV1SocialController@register',]);
        Route::post('/register', ['as'   => 'register', 'uses' => 'LaravelPassportHttpControllersAccessTokenController@issueToken',]);
    });

});

With the same json as before. That resulted in {"error":"invalid_client","message":"Client authentication failed"}.

I've tracked down the function that, I think, handles the validateClient part in vendor/leagueoauth2-server/src/Grant/AbstractGrant`.

The $client is null. Now this may or may not be related to Passport, since the documentation on it rather lacking and the thought of digging thru a monster of a package to track down the error that may be largely due to me not doing something right doesn't strike me as a good idea, I'm out of options. To be perfectly honest I don't even know what the problem is.

Really, at this point any sort pointing in the right direction is more than welcome.

The part in questions is

 Answers

34

The problem with Laravel 5.3 passport is that unlike previous OAuth 2.0 Server for Laravel library offered by lucadegasperi, it has no API to make clients directly. So as if now the client can only be made through the front-end. FYI we wanted to use laravel passport solely for our mobile app so while creating and registering user we would have only EMAIL & Password and in some cases only Facebook UserID for facebook sign-in. So the following approach worked pretty well for our case and might differ for your scenario but may help you in the longer term to play around with laravel passport.

Note: Before following the below its assumed you have enabled Password Grant in your application.

So the way we solved it for our project on laravel 5.3 is as follows:

  1. in the oauth_clients convert the id field into a normal field i.e. remove it as being primary key and make the data type as varchar so that we can store email address as client_ids as they are also unique for your system. Incase of Facebook login we store Facebook user IDs here in this column which again will be unique for each our client. Also for other tables like: oauth_access_tokens, oauth_auth_codes & oauth_personal_access_clients change client_id to VARCHAR(255) so that it can store email addresses or Facebook User IDs.

  2. Now go to your models and create a model for oauth_clients table so that you can create client programmatically from the code while creating users.

    <?php
    namespace App;
    
    
    use IlluminateDatabaseEloquentModel;
    
    class OauthClient extends Model
    {
        protected $table = 'oauth_clients';
    }
    
  3. Then in your api.php route file add the following route:

    Route::post('/register-user', function (Request $request) {
    
        $name     = $request->input('name');
        $email    = $request->input('email'),
        $password = $request->input('password'),    
    
        // save new user
        $user = AppUser::create([
          'name'     => $name,
          'email'    => $email,
          'password' => bcrypt($password),
        ]);
    
    
        // create oauth client
        $oauth_client = AppOauthClient::create([
            'user_id'                => $user->id,
            'id'                     => $email,
            'name'                   => $name,
            'secret'                 => base64_encode(hash_hmac('sha256',$password, 'secret', true)),
            'password_client'        => 1,
            'personal_access_client' => 0,
            'redirect'               => '',
            'revoked'                => 0,
        ]);
    
    
        return [
            'message' => 'user successfully created.'
        ];
    });
    

In the above code snippet, you have to note that to generate the oauth_client secret you have to use some strong formula of encryption that you feel comfortable using it with your application. Also, use the same technique to generate the secret key on your mobile app for the respective client/user.

  1. Now you can use the standard POST API offered by laravel passport to request access token through password grant using "oauth/token" using the following parameters:

    grant_type : 'password'
    client_id  : '<email with which the user is registered>'
    client_secret : '<generate the client secret from the mobile app>'
    username : '<email with which the user is registered>'
    password : '<password entered by the user>'
    scope : '<leave empty as default>'
    
  2. The above will give you a response, if everything is correct, similar to :

    {
      "token_type": "Bearer",
      "expires_in": 3155673600,
      "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3In0.eyJhdWQiOiJzaHVqYWhtQGdtYWlsLmNvbSIsImp0aSI6IjMwZmM0MDk1NWY5YjUwNDViOTUzNDlmZjc2M2ExNDUxOTAxZjc5YTA5YjE4OWM1MjEzOTJlZmNiMDgwOWQzMzQwM2ExZWI4ZmMyODQ1MTE3IiwiaWF0IjoxNDc4MTQ1NjMyLCJuYmYiOjE0NzgxNDU2MzIsImV4cCI6NDYzMzgxOTIzMiwic3ViIjoiMSIsInNjb3BlcyI6W119.dj3g9b2AdPCK-im5uab-01SP71S7AR96R0FQTKKoaZV7M5ID1pSXDlmZw96o5Bd_Xsy0nUqFsPNRQsLvYaOuHZsP8v9mOVirBXLIBvPcBc6lDRdNXvRidNqeh4JHhJu9a5VzNlJPm3joBYSco4wYzNHs2BPSxXuuD3o63nKRHhuUHB-HwjVxj2GDwzEYXdZmf2ZXOGRJ99DlWGDvWx8xQgMQtd1E9Xk_Rs6Iu8tycjBpKBaC24AKxMI6T8DpelnFmUbMcz-pRsgCWCF_hxv6FpXav3jr1CLhhT58_udBvXjQAXEbtHeB7W_oaMcaqezHdAeOWDcnqREZHsnXHtKt0JpymcTWBkS2cg7sJzy6P9mOGgQ8B4gb8wt44_kHTeWnokk4yPFRZojkHLVZb8YL6hZxLlzgV1jCHUxXoHNe1VKlHArdlV8LAts9pqARZkyBRfwQ8oiTL-2m16FQ_qGg-9vI0Suv7d6_W126afI3LxqDBi8AyqpQzZX1FWmuJLV0QiNM0nzTyokzz7w1ilJP2PxIeUzMRlVaJyA395zq2HjbFEenCkd7bAmTGrgEkyWM6XEq1P7qIC_Ne_pLNAV6DLXUpg9bUWEHhHPXIDYKHS-c3N9fPDt8UVvGI8n0rPMieTN92NsYZ_6OqLNpcm6TrhMNZ9eg5EC0IPySrrv62jE",
      "refresh_token": "BbwRuDnVfm7tRQk7qSYByFbQKK+shYPDinYA9+q5c/ovIE1xETyWitvq6PU8AHnI5FWb06Nl2BVoBwCHCUmFaeRXQQgYY/i5vIDEQ/TJYFLVPRHDc7CKILF0kMakWKDk7wJdl5J6k5mN38th4pAAZOubiRoZ+2npLC7OSZd5Mq8LCBayzqtyy/QA5MY9ywCgb1PErzrGQhzB3mNhKj7U51ZnYT3nS5nCH7iJkCjaKvd/Hwsx2M6pXnpY45xlDVeTOjZxxaOF/e0+VT2FP2+TZMDRfrSMLBEkpbyX0M/VxunriRJPXTUvl3PW0sVOEa3J7+fbce0XWAKz7PNs3+hcdzD2Av2VHYF7/bJwcDCO77ky0G4JlHjqC0HnnGP2UWI5qR+tCSBga7+M1P3ESjcTCV6G6H+7f8SOSv9FECcJ8J5WUrU+EHrZ95bDtPc9scE4P3OEQaYchlC9GHk2ZoGo5oMJI6YACuRfbGQJNBjdjxvLIrAMrB6DNGDMbH6UZodkpZgQjGVuoCWgFEfLqegHbp34CjwL5ZFJGohV+E87KxedXE6aEseywyjmGLGZwAekjsjNwuxqD2QMb05sg9VkiUPMsvn45K9iCLS5clEKOTwkd+JuWw2IU80pA24aXN64RvOJX5VKMN6CPluJVLdjHeFL55SB7nlDjp15WhoMU1A="
    }
    

Its only a temporary solution till laravel supports an external API for applications which only has a mobile as the only possible interface for creating oAuth clients and user.

Hope it helps you! Cheers.

Wednesday, March 31, 2021
 
ChronoFish
answered 7 Months ago
26

You can achieve it in many ways, following two liner :

$schedule->command('payments:create')->monthlyOn(1, '15:00');
$schedule->command('payments:create')->monthlyOn(15, '15:00');

if you would like to force a task to run even in maintenance mode, you may use the evenInMaintenanceMode method:

$schedule->command('payments:create')->monthlyOn(15, '15:00')->evenInMaintenanceMode();
$schedule->command('payments:create')->monthlyOn(1, '15:00')evenInMaintenanceMode();

Another ways (Laravel 5.4 onwards) onliner to schedule the event to run twice monthly.

$schedule->command('payments:create')->twiceMonthly( 1, 15);

If you want to run at specific time then use ->at(); method.

$schedule->command('payments:create')->twiceMonthly( 1, 15)->at('13:00');// At 1 PM of every 1st and 15th of every month

Another way to excute Crontab at midnight of every 1 and 15 of every month

 $schedule->command('payments:create')->cron('0 5 1,15 * *');
Saturday, May 29, 2021
 
Viralk
answered 5 Months ago
73

As stated at Google Maps Android API v2 Documentation:

Note: The info window that is drawn is not a live view. The view is rendered as an image (using View.draw(Canvas)) at the time it is returned. This means that any subsequent changes to the view will not be reflected by the info window on the map. To update the info window later (e.g., after an image has loaded), call showInfoWindow(). Furthermore, the info window will not respect any of the interactivity typical for a normal view such as touch or gesture events. However you can listen to a generic click event on the whole info window as described in the section below.

Perhaps you should try to call showInfoWindow() somewhere again in your code.

Saturday, August 7, 2021
 
andrews_nz
answered 3 Months ago
89

Apologies if my original question is not that useful in the first place, but...

I found that my combination of passport, passport-local, and passport-local-mongoose, a solution was to simply create an invalidation method on my mongoose Schema (that has the passportLocalMongoose "plugged in", and when my /logout route gets hit I essentially remove that user's token. Here's that method:

Account.statics.invalidateUserToken = function(email, cb) {
    var self = this;
    this.findOne({email: email}, function(err, usr) {
        if(err || !usr) {
            console.log('err');
        }
        usr.token = null;
        usr.save(function(err, usr) {
            if (err) {
                cb(err, null);
            } else {
                cb(false, 'removed');
            }
        });
    });
};

I presume it's more interesting to see this in context so again please feel free to refer to the repo listed in question...hope this helps someone.

Also, if a core from one of the aformentioned libs wants to suggest a better way I'd of course love to refactor my code to make it idiomatic; if not, this approach seemed to work.

Wednesday, August 11, 2021
 
Dev
answered 3 Months ago
Dev
61

I ran "php artisan ide-helper:models" -> Yes, it wrote some line in my models file and still not work I ran again "php artisan ide-helper:models" -> No, it created a new file called _ide_helper_models.php file but still not work.

FINALLY

I access file _ide_helper_models.php and add this function into class Article it work xD

/**
 * Add an "order by" clause for a timestamp to the query.
 *
 * @param string $column
 * @return IlluminateDatabaseQueryBuilder|static 
 * @static 
 */
public static function latest($column = 'created_at'){
    return IlluminateDatabaseQueryBuilder::latest($column);
}
Tuesday, August 24, 2021
 
user3599828
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share