Accessing APIs / Data in Laravel Passport from a Front-end Client - php

I am creating a niche community site+forum where users can sign up, log in, create posts and follow each other.
My tech stack consists of backend APIs in Laravel (using Laravel passport), and a front-end in Vue.js / Nuxt.
I can access all the APIs through Postman, where I call http://localhost:8000/oauth/token to request the token
https://laravel.com/docs/master/passport#requesting-password-grant-tokens
and then subsequently, I call an API using the provided access_token / bearer token, like
http://127.0.0.1:8000/api/v1/tags
My question is, do I NEED a full oauth flow -- my front-end will indefinitely need access to the backend APIs / data in Laravel, but how does the client get access to the data without going through a 2-way handshake with each user session, which seems like overkill?
Do I need a Password Grant Token, an Implicit Grant Token, a Personal Access Token, something else?
How do I "whitelist" my front-end javascript client while also somewhat protecting my data from bad use? Also, how do I use Passport to authenticate different types of API requests?
Is the Password Grant token appropriate for all of these.... I have 3 broad categories of data available in the APIs:
Type 1: Fully open, no Auth, not tied to a user: Examples:
GET /api/tags - API that gets all tags, this should not require authentication + authorization. This API would be used to display all tags on the /tags page, for example.
Type 2: Admin-only endpoints: Fully closed, not available to anyone, but for me (the Admin). Examples:
POST / PATCH / DELETE /api/tags - APIs that create / update / delete (global) tags, these should only be accessible by me (Admin)
GET /api/users - should only be accessible by me (Admin)
Type 3: User-specific endpoints, Available to a logged-in user only (and of course the Admin). Examples:
POST / PATCH / DELETE /api/user/1/settings - APIs that create / update / delete (user-specific) data, these should only be accessible by a logged-in user, and by me (Admin).
Is the Password Grant token appropriate for all of these?

Implicit grant is usually the best approach for an API driven/SPA.
Since the SPA is a public client, it is unable to securely store information such as a Client Secret. Using the Implicit Flow streamlines authentication by returning tokens without introducing any unnecessary additional steps.
The link to Laravel Passport that you provided to the implicit flow, also goes into detail describing that this type of flow is best used in javascript front apps: https://laravel.com/docs/5.8/passport#implicit-grant-tokens
Hope this helps!

Related

PHP / REST - How do I implement a role based access of my API?

I have started a PHP project (A Project Management Item Tracking Tool) using an API centric approach and have made a fairly good start.
I have created 2 GET the methods so far I want to restrict access but don't know where to start.
In the context of my database
Project is the container that encapsulates different actionitems.
Actionitems are 'assigned' to a user.
Users exist in a database.
Roles as assigned to a user. (User, Admin, Super)
User can only update their own item
Admin had create and update privilege
Super has total administrative privilege
My question is: Where should I start in PHP to only allow
accessing the api via proper users, either via a login api, or some
other means? Any help to get started would get me going.
To start I have successfully created an endpoint to access access resource (actionitems) using a JSON string to test the response.
Existing Endpoints I want to restrict
GET /api/actionitems/
With a general structure to access specific resources within a table as follows:
GET /api/actionitems/4
Note additional api endpoints should be accessed as follows
each route as up to 3 route tokens (following the /api/)
GET /api/users/123/actionitems (get all actionitems for user 123)
GET /api/users/123/actionitems?<more-filers> applies further filtering
You need to handle authentication and authorization for your APIs.
These are very basic steps to understand the solution:
Client calls login API using user credentials(username, password).
Server authenticates user credentials and generates a token.
Server stores this token in database against authenticated user id and responds to client.
Server already has authorization role rights to access different APIs associated with this authenticated user in database.
Client calls resource APIs using token provided by login API.
Server verify token in database and fetch user and user role rights against this token for authorization.
Resource APIs authorize and provides required data or perform actions according to authenticated user role rights.
There are multiple ways to achieve this in standardize way:
3 Common Methods of API Authentication Explained
JSON Web Token
oAuth2.0
You probably want to look at JWT tokens
https://jwt.io/
Here's some quick informations
An API with a token is stateless, you have to send the token on every request , generally in the Authorization Header, the token can contain a payload with some data like the user id the creation and expiration time.
On the server side, when you receive a token with a request you can just find the user id inside the payload and find the corresponding user in the database.
Since the token cannot be modified without the private key you can trust the data you receive.
Then you can just check if the user has some Admin or Super admin roles or if the item belongs to him and send the correct response.
Note: The payload inside the token is public meaning that everyone can read it, don't put any sensive informations.
If you want to use some long term authentication you can use refresh token with jwt tokens, they are stored in the database and can be used to create a new jwt token.
Hope this can help.

What is the best is the best OAuth grant to use in developing a front-end only app

I am very new to OAuth and I intend implementing an api for a frontend only (html and JavaScript) web app with login abilities using laravel Passport. Both the frontend app and the API server will reside on different servers. I have read a lot about different grants but still confused about which will be best suited for what I intend doing. Are the access tokens going to be stored on the front end (using local storage or cookies)? I am just confused about where to even start from.
I would suggest using the Implicit grant which is designed for browser applications. You can keep tokens in the sessionStorage (or the localStorage if you want to share them among browser tabs). OAuth2 tokens should sent as Authorization: Bearer tokenstring HTTP request headers, so cookies are not a good place for storing them.
There are two token types you can use:
Access token - if you want to use the token for authentication, access tokens hold scopes - information what actions the client is allowed to perform on behalf the person who was authenticated. Access tokens are often just random strings, so to validate it, the backend needs to ask the /token endpoint to get info about their validity and about the person who authenticated it.
ID token from OpenID Connect (OAuth2 extension) - in JWT form, ID tokens hold info about the person who authenticated them, can be validate offline, but cannot be used for authorization - they don't hold any scopes.
Bot token types have limited lifetime, you will have to get new token before the original one expires (using &prompt=none request see the OpenID Connect RFC).

Laravel Passport - How to login via webapp?

I've set up a central app (let's call this maindomain.com), where I've setup Passport. This site will be where users register to gain access to all other apps I create.
To test it out, I've followed Matt Stauffer's blog post to create a client app that will use the user data stored on maindomain.com, let's call this app1.com.
I can confirm that my callback and whatnot work fine. When you go to app1.com/login (as per my route) it redirects to maindomain.com and allows you to authorise app1.com to use your login details - beautiful.
As per Matt's post, right now it prints the token to the screen. I need to change this so that it saves to the database - I assume I should just create a column on my user's table and store it there?
I've tested the token and can access the API routes using Postman. However, because at the moment I'm creating web apps that all need to use this centralised user system, I'm not sure how I can use a login form to authorise users and allow them access to their dashboard.
If user's are logging into app1.com do I send a POST request to maindomain.com? Isn't that going to be a problem with CSRF? I've read the documentation but as this is my first venture into Oauth2 I am pretty confused.
If you want your login form to reside on app1.com, your only choice is Password Grant flow - app1.com will get user credentials and make a POST request to oauth/tokens on maindomain.com trying to get an access token. This POST request may happen in front-end or in back-end (more secure - client password will be hidden), that's up to you.
Otherwise, it sounds like your Authorization Code flow is already up and running. You could just keep redirecting users to maindomain.com (Facebook and most other OAuth2 providers choose this way), use the login form there, and then redirect back and fetch access token based on authorization code. Save that code in your app1.com database and allow users to access dashboard using that. When it expires - start the flow again.
Try watching this video by Taylor (the creator of laravel) to get going:
https://laracasts.com/series/whats-new-in-laravel-5-3/episodes/13
I created repos for both project and confirmed them working as they should:
API Server:
https://github.com/jeremykenedy/laravel-passport
API Consumer:
https://github.com/jeremykenedy/laravel-consumer
Try making protected API end-points in the routing file api.php and use token scopes if needed to further protect the API endpoints :)

Implementing OAuth 2.0 authentication with a Laravel API

I'm currently building a web application which is an AngularJS frontend that communicates with a RESTful API built using Laravel. I'm making good progress, but finding it hard to get my head around how to handle user authentication.
I've been advised that I should be using OAuth for authentication, and I've decided to use it seen as it could be a learning experience for me as well. The package I'm using to handle this is oauth2-server-laravel.
The basic user story is that users can register their username/password combination for the application, and they then log into the application with that same username and password. They're only authenticated by their username and password, and not by any client secret. After login, they should be given an access token which will be send along with every future request to authenticate them on different API endpoints.
The OAuth2 library has a "password flow" grant type which seems to be what I need, however it also takes client_id and client_secret parameters, which I don't want. The request URI is something like this:
POST https://www.example.com/oauth/access_token?
grant_type=password&
client_id=the_client_id&
client_secret=the_client_secret&
username=the_username&
password=the_password&
scope=scope1,scope2&
state=123456789
But what I want is just:
POST https://www.example.com/oauth/access_token?
grant_type=password&
username=the_username&
password=the_password
How am I meant to provide a client ID and secret of a user that has yet to authenticate?
Is there a different grant I can be using, or is what I want to achieve just not suited for OAuth at all?
Take into account, that client id and client secret aren't parameters that you have to force your end-user to pass. They are static and defined in/for your client app (angular app in this case).
All you need to do is to create a record for your main app in oauth_clients table, and create a scope with full access in oauth_scopes table, and send this values when requesting token.
And that's all in fact.
Also, you may want to consider using implicit grant flow in case of building js-only application, because storing client secret and refresh token in a js app is insecure. Using implicit grant in a final product may look like login window on soundcloud and is more secure as the token is obtained server-side without exposing client secret.
Another way to go, if you still want to use password flow is creating a proxy for refreshing tokens. Proxy can hide your refresh token in encrypted http-only cookie, and your js-app don't ask your api for new token, but the proxy instead. Proxy reads refresh token from encrypted cookie, asks the api for new token and returns it. So the refresh token is never exposed. If you set token ttl for an hour let's say, then stealing a token would be quite "pointless*" in case of a normal application, and stealing refresh token would be "impossible*".
*Of course if someone really want he probably could hack it any way.
And yeah, i know this all looks a bit hacky - modal windows for logging in, proxy etc. But also searching on this topic i couldn't find any better and more elegant way of doing it. I think that's still a lack that all js-apps have to deal with if you want a token based authentication.
You are missing something with the OAuth specification. The client_id and client_secret are really important when asking for an access token when using the password method of OAuth v2. In fact, they are important for every method that gives you an access token. They identify the application or the server that has perform the request.
For example, let's say you have your API, 2 mobile applications and another server that do some tasks with your API. You will create 3 clients with their own client_id and client_secret. If your application has various access levels (they are called scopes in OAuth v2), the client_id corresponding to the other server will be able to call functions of your API that require the scope admin whereas your mobile application will only be able to call functions of your API that require the basic scope if you have defined scopes like this.
If your API grows up in the future, this is really essential. Another example, let's imagine you have given an API key (a pair client_id and client_secret) to one of your friend and he has build a nice mobile app with your API. If one day he starts doing naughty things with your API, you can't stop him very easily. Whereas you could have just removed his key pair if you had followed OAuth v2 principles.
OAuth v2 is not an easy thing to understand, take the time to read specifications and good tutorials before developing your API.
Some useful links :
The official RFC : https://www.rfc-editor.org/rfc/rfc6749
A tutorial on Tutsplus : http://code.tutsplus.com/articles/oauth-20-the-good-the-bad-the-ugly--net-33216
Just to add a bit to plunntic's excellent answer: remember "client" is not related to "user", so when I use a password flow I just define the client_id and client_secret as constants on the AngularJS app to tell the api backend: hey, this is the browser app that is being used to request a token.

OAuth2 client without access token

So before I start, I'm a bit of an OAuth2 newbie, so still trying to really wrap my head around the various permission scopes and grants.
I've managed to successfully implement an OAuth2 server using the Laravel OAuth2 Server package.
The current site I'm working on will simply dogfood from the API, using the client_credentials grant type. I've managed to get this successfully working and can make API calls with the provided access token.
However, I'm wondering how I can implement an architecture similar to Instagram, Soundcloud, etc, who don't require an access_token for basic endpoints, just a client_id. How do they do this? Is this a custom grant type?
Preferably, I'd only like to start requiring an access token when accessing private resources, such as those for modifying user information, etc. As far as I'm aware, for these I'd need to use the password grant type, which isn't a problem.
OAuth has a few flows such as 2-legged or 3-legged which basically tells the developer how many requests he needs to make to the server to get the resource he wants.
For example, in a 2-legged flow you send a request with your id and secret (first request), you get back an access_token and using that token you can make other request for the resource you want (second request).
Comming back to your Instagram example, you can think at using just client_id as a 1-legged OAuth flow, because you make only one request to server to get the resource you want.
You can use such a flow for less sensitive resources, like a profile photo or user's nickname for example.
The implementation of a 1-legged flow is simple:
- If the user_id is valid and the application doesn't need user approval to access requested resource, go ahead and show the resource.
So implementing a 1-legged flow consists in checking if the client_id is valid and checking if the requested resource needs user permission. That being said, you can use 1-legged for requesting a user profile photo, but you can't use the same flow for requesting the user's private messages.
You can read more about each OAuth Flow in The OAuth Bible.
You have two different resources on your server - a) Resources that need some access checks b) Resources that are publicly accessible.
Actions on resources that need access checks should require that a user has been identified via the OAuth header in the request. In the context of Laravel - this would be a route with the 'before' key specified as Oauth.
Actions that do not need access could glean context about what user is relevant by building your routes to accept an argument that gives you context about the user. Let's say that you have a profile that a user can see without any sort of access. Your API endpoint for a JSON representation of that could be /api/profile/[user_id], where [user_id] is the ID of the user profile you would like to see. For these routes where you do not care about access, you can leave off the oauth before filter in your route declaration.

Categories