Laravel Passport - Authenticate using postman - laravel

I have setup Passport in Laravel 5 and am creating a token when a user registers by using this..
$user->createToken('My Token')->accessToken;
When I create a new user then I can see an entry in the oauth_access_tokens table that looks like this, I have shortened the id for display...
id | user_id | client_id | name | scopes | revoked
-----------------------------------------------------------
765765 | 193 | 1 | My Token | [] | 0
The API route I want to allow access to is protected, now I am trying to allow access by passing the following headers in Postman...
Authorization | Bearer 765765
Accept | application/json
But this is returning a response of unauthenticated, where am I going wrong?

Laravel Passport uses oAuth2. It's not as simple as generating a user token and being able to use it to authenticate. oAuth2 requires another step, which is called a token exchange.
You will have seen the oAuth2 process in action when you log into a website with Facebook. You click the login with Facebook button and you are sent to Facebook and you are presented with a dialog where you're asked to confirm or deny an app access to your account (Usually, specific parts of your account, a.k.a scopes).
That website will have it's own client account with Facebook and will have its own client ID and client secret. When you click that button, the website sends you to Facebook in order to gain your permission and an authorization code from Facebook. The website passes its client ID, requested permissions (scopes), a randomly generated session state (So it can verify later) and a URL to redirect to Facebook where you are shown the dialog.
When you accept, Facebook generates what is called an authorization code and sends you back on your way to the website (The redirect URL specified) along with the sessions state (So the website is able to verify the request) and the authorization code.
The website, on its back end will then ask Facebook to exchange your authorization code for an access token and will provide its client ID and client secret so Facebook is able to verify its authenticity. Facebook then responds with an access token and an expiry time.
Now, the website is able to access your account using the access token to be able to grab the requested information (Such as your email address for login).
It's also possible to do skip a lot of this process and not require the user to have to follow the whole redirection flow. To do this, (In Passport at least), you will need a password grant client. This is usually what you would do if you are using oAuth2 to authenticate an API.
The process here would be to generate a password grant client:
php artisan passport:client --password
In your database, the you will find in the oauth_clients table, a password grant client with a client ID and secret. You would need to give this to whoever is consuming your API (Such as a mobile/cellphone app).
Now when your user wants to log in, the consumer of your API (In this case Postman) would need to provide the user's credentials (username/password) as well as the client ID and secret for your password grant client. It's also necessary to tell Passport that you want to authorize via password grant.
The example given in the docs looks like this:
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'taylor#laravel.com',
'password' => 'my-password',
'scope' => '',
],
]);
When successful, Passport will return a 200 response and will return some JSON containing an access token and a refresh token. You use the access token to access the user's account and you use the refresh token to get a new access token (without requiring the user to log in again).
It is this access token that you need to provide as the Bearer in your Authorization header.

Related

Issue understanding Laravel 6.0 Passport with Password Grant Tokens flow

I'm having issues understanding the whole process of authenticating a client to consume my API built on Laravel. Some things just don't click for me right now.
I'm trying to implement an API and an OAuth server both on Laravel. The API will be consumed by a native mobile app that is trusted. The flow that makes more sense to me is "Password grand token" as described in the Laravel's Passport docs: https://laravel.com/docs/7.x/passport#password-grant-tokens
As i understand the implementation:
User installs my mobile app.
Upon installation, he's prompted with the "enter username/password" to continue to use the app
Upon hitting submit, i make a POST request to my Laravel oAuth server implementation on "/oauth/token" with "grant_type", "client_id", "username", "password", "scope". I'm leaving out the "client_secret" because i understand that it's not a good idea to store the secret on the client device.
The server then checks the already created( `php artisan passport:client --password` ) "client_id", "username", "password" and "response_type"
If all matches, it generates a token, and responds with "acces_token" & "refresh_token"
I can make now make calls to my API's endpoints "/api/whatever/method_name"
My issue is at point 4. I can only issue the access token if the user already exists in my database, but i'm assuming it's the first time the user uses my app. postman_response
Do i also need an "authentification" step, in witch the user sends username/password and the OAuth server prompts the "authorize app" to use your data, and at this point to save the user in the database and only then proceed?
Usually you have an register route, that is without authorization else you have no entry into the application. Imagine your routes file.
Route::middleware('auth:api')->group(function () {
Route::post('/todos', 'TodoController#index');
});
// Without auth
Route::post('/register', 'RegisterController#register');
For hiding credentials, it is often easier to do a proxy approach, so you backend can hold client_id and client_secret, since it will always be the same (unless you are building an oauth server).
Route::post('/login', 'LoginController#login');
Which will receive username and password, internally call oauth/token and add client_id and client_secret in the process and return the token. To save some calls through the signup, you can do the same approach after you have registered, get the oauth token, with the credentials you have at registrering and return the token imediatly.
I would recommend the following:
In log in method, check if user exists.
If exists, do log him in.
else, first register him up, and then log him in
lastly, return access token

Laravel Passport APi - Implicit grant

I want to build a spa via angularjs and use laravel as a api for the spa. Reading trough the docs of laravel passport i discovered that i need to use the implicit grant for this purpose. But i am not really sure in how it should work from front to back. I just want to have the ability to log in a user with a username and password and then just use it and i need some clarification on the process. This is what i want:
Log in with a user by a username and password via html/javascript to laravel (Angular) via an ajax request.
Get an access token to communicate with the api
Do some action in the spa that triggers a request to the api using the access token
Getting data back from the api in response to that request.
But what i see now with the implicit grant i a bit different than what i expect.
Log in to laravel via a default blade login form (did not create one using ajax yet)
Redirect to oauth/autorize like this
Route::get('/redirect', function () {
$query = http_build_query([
'client_id' => 'client-id',
'response_type' => 'token',
'scope' => '',
]);
return redirect('http://your-app.com/oauth/authorize?'.$query);
});
The redirect shows an approve or deny authorization request screen (this is not what i expect)
When i approve the request, the browser redirects me to the redirect uri that is specified in the oAuth client database entry with the access token. And i should be able to.
What confuses me even more is the fact that i seem to need a new client for each laravel user. I expect to have 1 oauth client representing my spa that can access the laravel users. Could you please clarify this?
If you are going to use a password grant in a JavaScript application then you must use a server side proxy to do the authentication and secure both client_secret and the refresh token.
The proxy manages the whole api communication process or just the authentication part and returns a short lived access_token . Authentication state is managed via a server session. Some requests must be protected from CSRF exploits depending on your implementation since most implementations use a cookie.
Otherwise use an implicit grant to authenticate your app. (See links below for more info)
https://auth0.com/docs/api-auth/tutorials/implicit-grant
https://oauth2.thephpleague.com/authorization-server/implicit-grant/
You can refresh your access token using silent authentication as described here
https://auth0.com/docs/api-auth/tutorials/silent-authentication
NB: In most cases refresh tokens do not expire, that's a big NO for Frontend storage.
Client Secret should always be kept secret.
Edit (2020)
It's now 2020 and a lot has changed in the web security world.
There are known vulnerabilities with implicit grant especially since your access_token can be intercepted mid-flight and redirected to another server.
It's now recommended to use PKCE flow instead of implicit grant
Okta has a very nice article and video regarding this Is the OAuth 2.0 Implicit Flow Dead?
Laravel has also released a much simpler alternative Laravel Sanctum I suggest you have a look at it as it uses secure HTTP only cookies for access token storage and also implements CSRF protection out of the box

Laravel API Passport Token

I have a question about laravel passport... I did the code and it is working very good, my question is about the token.
My friend has an mobile app which it will connect to my Laravel API... I already gave him a grant token my question is, do I have to give him a new token everytime that he wants to connect to the API? or just with that one is enough? one token and it works everytime?
I think that it works like this:
He wants to connect.
He passes the token to access to the API.
The API creates a response.
Am I correct?
For mobile application you should use password grant for Api protection. For password grant, the general concept is the API will give the app client the following parameters for accessing the auth client to get an access token and refresh token.
grant_type: password
client_id
client_secret
When the user login in the mobile application, the mobile app will use the above parameters and also the user's username and password to request a user specific access token, this token usually will be active for 60 minutes, after 60 minutes, the app client need to use the refresh token to get a new access token.
After getting the user access token, for the rest of your APP's api, the mobile client need to use this access token to access them.
For Laravel Passport, you can check out the password grant document here:
https://laravel.com/docs/5.4/passport#creating-a-password-grant-client
To understand more about what password grant is check out this link:
https://www.oauth.com/oauth2-servers/access-tokens/password-grant/
Note: From what I understand from your description, the grant type you are using is Client Credential Grant, this type is best for using system to system API authentication.

OAuth2 password grant confusion

I have read below article and it is just awesome. Everything from that article is clear however I have one major doubt.
https://stormpath.com/blog/the-ultimate-guide-to-mobile-api-security
The article author said that in 'OAuth2 password grant' while logging into the mobile application, just need to send email and password in order to get the access token from the API server, but I have read at many places that you also need to send client_id and client_secret in that request. I'm going to build my API using Laravel:
https://laravel.com/docs/master/passport#password-grant-tokens
Here you can see it forces me to send client_id and client_secret in that request.
I'm really confused about this. If I have to send client_id and client_secret in that request, first I need to get it from the authorization server by creating a client on it. So at which event, I should create that client? When a user tries to log in from the mobile application? I just need to know the exact flow.
Any help would be appreciated.
Thanks
A client gets created for the developers who need to integrate with the OAuth2 server. It has nothing to do with the specific users' login flow.
ex. I want to integrate with Facebook login; I create a client on Facebook and incorporate that into my service, its Facebooks way of knowing who my service is.
So, a user logs in through your application; your application then sends that username and password to a backend server. The backend server then adds the client_id and secret so the OAuth server can verify the authenticity of the request.
So in your case, a user logs into your mobile application, you send that login request (username and password, with SSL) to your backend server. Your backend server then forwards that request to the OAuth2 service looking like the request below.
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'user#email.com',
'password' => 'user-password',
'scope' => '',
],
This directly returns an access_token and a refresh token that you can safely store in your mobile application.
I create the grant client in a migration called ConfigurePassport and set the key i want the app to use. You do not need a client per user.
public function up()
{
/*
* This command will create the encryption keys needed to generate secure access tokens.
* In addition, the command will create "personal access" and "password grant"
* clients which will be used to generate access tokens
*/
Artisan::call( 'passport:install', array('-n' => true) );
// Set Password Grant Client secret to known key
DB::table( 'oauth_clients' )->where( 'password_client', 1 )->update(
['secret' => env( 'GRANT_CLIENT_SECRET', 'dfhsdfhbtg545fdf45yedh5f5blahblah' )]
);
}
The above migration runs the artisan command passport:install as per the documentation to install the client. https://laravel.com/docs/master/passport#password-grant-tokens
Now your mobile app can request a token like so: the unique per user params are username and password.
You can find the client id in the oauth_clients table where password_client is true. It will likely be 2.
$http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 2,
'client_secret' => 'dfhsdfhbtg545fdf45yedh5f5blahblah',
'username' => 'taylor#laravel.com',
'password' => 'my-password',
'scope' => '',
],
]);
There are two different concepts:
Client: is the piece of software that's intended to communicate with your server. Usually, you will have 3 main clients which are your iOS, Android and web apps.
User: Which is the end-user that will interact with one of your clients, then the client will be communicating with the Oauth server on behalf.
So you will need to generate a client_id & client_secrete only one time. Then you can use these keys to be the authorized middle-man between your Oauth Server & the end-users.
In the case of Password Grant, The client_key & secrete_key are used to obtain the access_token for every user of each client you have.
Once the client obtains the access_token of a particular user (usually upon logging-in), the client will not need to send the client_key & secrete_key anymore, only the access_token.
However, if that user's access_token has expired, you will have to use those keys to exchange a new access_token with the refresh_token you already received from the login process.

OneDrive App Access Token

Does anyone know how to get the app access token to a One-Drive API app?
I've tried combining {appId}|{appSecret} as the access_token param and as the Authorization header but it doesn't seem to work.
Thanks,
The OneDrive API docs have a good section on getting auth tokens with OAuth. In a nutshell, there are two services involved -- the OneDrive API service and the authentication service. The OneDrive API only accepts OAuth tokens that were issued by the authentication service. The authentication service is what you talk to first to get an auth token.
Depending on your app, you can either use the token flow or the code flow to get an auth token. In the 'token' flow, you navigate the user's browser to the authentication endpoint with your appId. The user may need to log in, consent, etc., and then the authentication endpoint redirects back to your site with an auth token you can use. The 'code' flow is similar to the 'token' flow, except it redirects back with an authentication code that your client app can use (along with its client secret) to obtain an auth token and a refresh token. Once you have a refresh token, you can use that to obtain future auth tokens without the user's involvement (as long as they granted the wl.offline_access scope).

Resources