Restful authentication and authorization - php

I'll build a single page web app (with Backbone js) and make it consume a Restful API (in PHP) that I've to build too.
I wonder how to handle my user authentication to the API and manage the authorization when user request some data ?
I know that a restful api should be stateless but I'm stuck at this point.
Thanks

The authentication is easy.
You can handle sessions as resources:
POST /sessions {email, password}
-> {userId, token}
After that you can send back the token in a http header or in a cookie (better in http header because it protects you from CSRF attacks). I the service does not get token in the request header, than it can send back a 401 unauthorized response. If you cannot create the session, you can send back a 4** request, I use to send back 404 not found.
The authorization is harder.
You have to decide how granular you authorization system should be. It can be ACL, RBAC, ABAC, depends on how complicated your application and your access rules are. Usually people use ACL and RBAC hardcoded like this (fictive language):
#xml
role 1 editor
#/articles
ArticleController
#GET /
readAll () {
if (session.notLoggedIn())
throw 403;
if (session.hasRole("editor"))
return articleModel.readAll();
else
return articleModel.readAllByUserId(session.getUserId());
}
It works fine by simpler systems, but with this approach you will never have clean code because the access control should not be part of the business logic, you should externalize that. You can do that with an ABAC system, for example with an XACML implementation. (XACML is a great tool, but I find it a bit complicated.) You can create a custom automatic ABAC system with this approach too (same example):
#db
role 1 editor
policy 1 read every article
constraints
endpoint GET /articles
permissions
resource
projections full, owner
role 2 regular user
policy 2 read own articles
constraints
endpoint GET /articles
logged in
permissions
resource
projections owner
#/articles
ArticleController
#GET /
readAll () {
if (session.hasProjection(full))
return articleModel.readAll();
else if (session.hasProjection(owner))
return articleModel.readAllByUserId(session.getUserId());
}

Related

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

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!

oAuth user authentication in internal rest API

I am building a REST API service that will not be public and only used by the client to access the resources on the server. There is no authorization of different consumers as the only consumer is the server.
I understand that 3 legged oAuth is the standard used by public API's like facebooks and I think I'm correct in assuming I am after 2 legged authentication but I cannot find a useful website describing it.
I need to use oAuth to access resources and/or change them. Obviously this should be protected. But I am unsure as to how about doing this within PHP. So if a user requests something like https://example.com/me/follow/123 by a post request the user 123 would only be followed if the user is logged.
I would also like public resources to only be accessed by a recognized client only. So if you access https://example.com/user/123 a 401 is given but if you access https://example.com/user/123?client_id=890 a result is given. This will not stop users who are not logged in getting public resources but will stop users who are not using a recognised client. More than a anythinging this is a way for me to track what clients are using the API in the future.
1) How do you go about logins and give the users a token that is sent with every API request?
2) How do I protect the API from being used by unrecognized clients?
I am sorry if any of my terminology or ideas are incorrect. My understanding of REST and oAuth is still very much developing.
you have to use grant types=client credentials check it in OAuth standard point 4.4 https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-31#section-4.4
I agree that cleint_credentials grand is the most secure and standard way of app level authentication -- your client sends a request for an access token to a specific resource and includes their client_id and client_secret in the Basic Auth header like this:
Authorization: Basic {base64 encode client_id:client_secret}
Then all subsequent requests use the access token as a Bearer token like this
Authorization: Bearer {access_token}
However... if this is a purely internal API and you don't need super security, it is also acceptable to simply validate the client_id (or apikey) on every single call. It means your API will need to look up (or cache) the validity of the apikey.
I suggest you send the apikey as a header for security so it isn't exposed on the query params, but it is also acceptable to send the apikey as a queryparam like
/myresource?apikey={client_id}
Not recommended from a security standpoint, but accepted practice in the API world.

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.

PHP RESTful Webservice with Slim Framework, Authentification needed or against statelessness?

I'm writing a RESTful Webservice with the Slim Microframework and use GET for reading data from a mysql database (select query) and also POST/PUT/DELETE for insert/update/delete rows in the database.
My question is now, is this not a big security issue if everybody is able to write or delete data in the database? But how could I prevent this, I thought the ST in REST stands for state transfer (so the webservice is stateless), which is a contradiction to a state like being logged in or not. And if I would pass some login data with the client which is allowed to write in the database, couldn't a bad guy catch the logindata and fake requests with it and for example delete all entries?
So, whats the normal way to go with this, the only Slim Framework examples I had found always show the route examples, but not how to secure it.
Are there also some opportunities in the Slim Framework to implement this what I need? It should be as easy as possible and the request should be responded nearly as quick as without an authentification or similar. There are no sensitive data like passwords, for me it would be enough that not everybody with a cURL commandline tool can delete all rows or things like that.
Would be great if anybody could explain me what to do and/or give some examples. I also need to know, what I maybe will need to change at the clients which are allowed to send the requests.
Lots of thanks.
Each request has to be authenticated and authorised.
People often get tied up with the word 'stateless'. This really just means that from one request to the next, the RESTful service has no prior knowledge of the users state.
BUT, the service is obviously allowed to be aware of the authenticated user that has just made a request, else how would it decide if it should allow access?
Therefore, you can 'store' the authenticated user in some variable during each request. Then it's up to you how you use this information to authorize the request.
I like to keep it simple and have all my users as a resource in my URI chain. They make requests like users/{username}/someresource.
I authenticate using http basic authentication (over SSL) and authorise based on the URI. If the request failed authentication, its a 401 Unauthorized Request. If the URI {username} and authenticated {username} do not match, the request is a 403 forbidden. If it is authenticated and authorized, the request is allowed (http code dependant on http verb)
Now that's the web service covered, now on to the web service client. This of course HAS to store state, otherwise your user would have to log in every time they make a request.
You simply store the users session in the application (as per normal session management) with the addition that you store the username and password (encrypted of course) in the session. Now every time a request is made, your web service client needs to retrieve the username and password, and send it with the request to your web service.
It will be stateless, in the sense that there won't be a session or a cookie, really. You'd normally issue out a key that would be required for INSERT/UPDATE/DELETE.
It is then up to you to pass the key with each request and to determine when a key should expire.
It would be as safe as normal http authenticated sessions. These use a cookie etc to authenticate the connected user to the stored session state.
A stateless service would be no different - the token is passed to the service just as a token is stored in a cookie for normal http. If you are worried about sniffing (IE man in the middle attacks) you would secure the link via SSL.
The authentication token generated by the service would be encrypted and would include a salt which is also verified on the server for each request. You could also limit the session time to suit your paranoia, and also check changes in source IP, user agent etc and expire the user's token if these change.
I recently ran into similar problem. As recommended by people here, I have decided to go with OAuth Authentication.
I am using HybridAuth A php wrapper for OAuth and out of the box sign in solution for Facebook, Twitter, Google, LinkedIn, etc.

Building a simple RESTful api

I'm wanting to make an API quickly, following REST principles - for a simple web application I've built. The first place the API will be used is to interface with an iPhone app. The API only needs handle a few basic calls, but all require authentication, nothing is public data.
login/authenticate user
get list of records in users group
get list again, only those that have changed (newly added or updated)
update record
So, following REST principles, would I setup the uri scheme?:
mysite.com/api/auth (POST?)
mysite.com/api/users (GET)
mysite.com/api/update (POST?)
and the responses will be in XML to begin with, JSON too later.
On the website, users login with email and password. Should I let them get a 'token' on their profile page to pass with every api request? (would make the stand alone '/auth' URI resource redundant).
Best practices for structuring the response xml? It seems like with REST, that you should return either 200 ok and the XML or actual proper status codes i.e. 401 etc
Any general pointers appreciated.
1- for auth, you might want to consider something like http-basic, or digest auth (note - basic in particular is insecure if not over https)
for the urls scheme:
/api/auth is not needed if you leverage basic or digest.
/api/group/groupname/ is probably more canonical
/api/update would generally be done as /api/users/username (POST) with the new data added - the resource is the user - POST is the verb
otherwise, basically your API looks sane, much depends on whether groups are hierarchical, and users must live in a group - if so, your urls should reflect that and be navigable.
2- status codes should reflect status - 200 for OK, 401 for access denied, 404 for not found, 500 for error processing. Generally you should only return an XML record if you have a good request
Authentication in an API always works by sending some authenticating token in the request header. I.e., even when using the separate /auth login approach, you would return some token, possibly a cookie, back to the user, which would need to be send together with every request.
HTTP already provides a dedicated header for this purpose though: Authorization.
The most basic HTTP "Authorization" is HTTP Basic access authentication:
Authorization : Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Digest Authentication is another, more secure, scheme. You can use this header field for any form of authentication you want though, even your custom implemented authentication.
Authorization : MyCustomAuthentication foo:bar:n293f82jn398n9r
You could send the aforementioned login token in this field. Or you could employ a request signing scheme, in which certain request fields are hashed together with the password of the user, basically sending the password without sending the password (similar to digest authentication, but you can use something better than md5). That obliterates the separate login step. AWS employs this method.
For an API in general, make good use of the HTTP status codes to indicate what is happening.
You're generally on the right track. The URI scheme should be based around the idea of resources and you should use an appropriate method to do the work.
So, GET to retrieve info. POST (Or maybe PUT) to create/change resources. DELETE for well, delete. And HEAD to check the metadata.
The structure of your XML doesn't have much to do with a RESTful API, assuming it doesn't require state management. That said, you have the right idea. If it's a good request, return the desired XML (for a GET request) and status code 200. If it's a bad request, you may also, and in some cases needed to, return something other than just the status code. Basically, get familiar with the HTTP spec and follow it as closely as possible.

Categories