Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Should I use JWT or PHP sessions? Is developping API separated from frontend the right fit for me? #12

Closed
samuelgfeller opened this issue Nov 24, 2020 · 6 comments

Comments

@samuelgfeller
Copy link

samuelgfeller commented Nov 24, 2020

When I was thinking about how I was going to develop apps a some months ago I explained that I want a core part which is able to communicate with different clients (Browser, Native app, web service etc.) I got the advice to make the application as API with separated frontends.

Soon I adopted JWT and was confronted with the fact that there is no proper way to invalidate a token, that token were only valid for a given time and not depending on the user activity.

Additionally, each request has to contain all the infos since the API is (ideally) stateless.

Although this is great for some cases I am starting to think that it's not the right fit for what I want to do. I am reading that JWT should not be used for sessions (Why JWTs Suck as Session Tokens) and its kind of exactly what I was using them for.

What I want is to create an extensive example project that will be used as a base for larger applications which will basically have the standard functions (user registration, user login, user clicks around and does stuff, website uses the user’s information to create, update, and delete information).
Maybe native apps will be created on Android and IOS but most probably it will only be a PWA.

Is a REST API as Backend separated from the frontend the right approach in this case ? Or should I head towards doing backend and frontend in the same project folder and manage sessions with PHP ?

I like to build the whole content dynamically with AJAX requests so it made sense for me to call an external API (because it could be used by other frontends as well) but I have this above mentioned session issue now. I would basically have a backend that I treat like a non-stateless API which can be used only by this specific frontend.

I'm very interested in your opinion on all this Daniel.

@odan
Copy link
Owner

odan commented Nov 24, 2020

Indeed, a JWT should not be used as a replacement for sessions (cookies). There are some tricks to invalidate a JWT, but it still doesn't feel right to me.

For a typical web-application with login/logout functionality a cookie based session handling is still the best option (IMHO).
In a globally scaling web application with millions of users, cookies can also be scaled in the backend by sharing the session data on database servers (e.g. redis, Memcached or even MySql). But in >95% of all cases the file based session storage is simpler and "good enough".

It's definitely better and recommend separating the "Frontend API" from all other API's like the API for the native App or PWA.
For native apps I would implement a separate RESTful API that does not interfere with the web application specific (frontend) endpoints. It's possible to handle this with routing groups and route group specific Middleware in the same Slim project.

Except the frontend endpoints, I would put all "external" API endpoints into a /api/* URI path to keep it separated from the actual application routes.

Auth: You have to differentiate here.

  1. I would go with a session for the web-application routes.

  2. For all api/* routes the Auth mechanism depends on the context and client. Don't use Cookies for the API routes. Better use BasicAuth or a fixed Bearer-Token in the Authorization header or JWT. The best Auth method depends on your specific requirements (and know-how).

I'ts really important to distinguish all the different parts of your application. Luckily you can organize and handle all this different endpoints with routing groups and the middleware.

@samuelgfeller
Copy link
Author

Thank you a lot for this insight. Did I understand you correctly?

  1. JWT and thus backend as RESTful API are not suited for a typical web application with login and other functionalities because they should not be used for sessions.
  2. You would put external calls (from for e.g. native apps) in group /api/* to keep it separated and use BasicAuth or a fixed Bearer-Token in the Authorization header or JWT.
  3. It's better to have one backend (as API or not as API) fore each frontend for calls like GET /users/2 and UPDATE /users/sendEmailsToAllUsers.
  4. That would mean that the same "logic" has to be implemented thrice if there is a web app / PWA API, android app API and ios app API with the login system changing each time. There would be three times the method findUserInDb(int $id).
    No.. Actually I think you mean that there is three different routing groups, different middlewares, different Actions/Controllers but service and infrastructure layers stay the same, and everything is in the same Slim project, right?
  5. If the latter is right I don't understand why RESTful API for native apps since they too have to execute actions like sendEmailsToAllUsers. Or would that be caught by the RESTful API with a, in point 2 said auth system and transferred to the common service layer?

Everything is way clearer now and enough for my use case right now but I'm still missing a little something if one day I'll work with native apps.

@odan
Copy link
Owner

odan commented Nov 25, 2020

  1. You have to differentiate.
    1.1 Using JWT for "session" handling is not optimal for a typical web application.
    1.2 A RESTful API is good for the backend of a typical web application and APIs.

  2. Yes.

  3. Try to separate and group the routes (endpoints) per "client" (e.g. the native app) because it's another context with other use cases. You just create the routes you need for this specific context. Don't mirror all the same routes. Create another sub-path under /api/* for each type of "external" API.
    For example: GET /api/my-app/v1/users, GET /api/other-client/v1/users.
    Don't use method names (RPC style) for a RESTful API endpoints.

  4. The business logic must not be placed in a Action (or Controller) class. The Domain layer resp. the application- and domain services are responsible for the business logic. See ADR.

  5. The Single Action Controller is just a "Controller" and responsible for the HTTP specific stuff. The action just invokes the "Domain layer" by calling specific service method. The action takes the result from the service and renders it into a response.
    How you organize your Domain layer depends on your requirements and context. I do even separate the different client context in my domain by creating sub-modules and application services with namespaces. On a lower level you then may have common domain services that share the same logic.

@samuelgfeller
Copy link
Author

  1. A RESTful API is good for the backend of a typical web application and APIs

If I make sessions with the backend doesn't that mean that the important REST-principle stateless cannot be respected and thus it makes the API non-RESTful?

  1. Okay group for each client makes sense

Don't use method names (RPC style) for a RESTful API endpoints

I totally agree for RESTful APIs it's a nono but if point 1 is true, if it isn't RESTful, if it is only a backend that receives ajax calls (I called it API without preceding REST maybe it's not the right term), and it has to execute actions like notify technical contact or send bill via email, how would you name those actions in a non RPC way? Whenever possible of course restful naming but aren't there exceptions?

  1. Of course. At the beginning I was puzzled because to me, separating the "Frontend API" and separate RESTful API meant separate project folders, separate Slim applications in which case the logic had to be implemented in every one of them.
    Only in the second part I realized that you meant everything in one Slim project, clearly separated by route groups and different middleware. So all that different endpoints can access the same domain layer.

  2. I think the answer to this question was point 3, that native apps do not access the "external RESTful API" but have each one group for them.
    I think the word REST got us confused. For me the "frontend API"/ Backend which use sessions (reason why I made this question in the first place since JWT is not good for that) could per definition not be RESTful.

@odan
Copy link
Owner

odan commented Nov 25, 2020

Yes, the "Frontend API" is not a real RESTful API because it's not stateless when you use session cookies. REST(ful) is not a religion and should not be approached as such. While there are advantages to RESTful, you should only follow the tenets of REST as far as they make sense for your application. When you name your routes like methods then it's more a RPC'ish API. Just because it's not stateless doesn't imply that you have to name your HTTP routes like method names. I try to be consistent with all route names. I would try to avoid mixing RPC'ish names with RESTful names.

@samuelgfeller
Copy link
Author

Thank you for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants