According to the documentation since OctoberCMS v3 it is possible to build API endpoints using Twig.
I read that it is also possible to use layouts as middleware in this case and add condition to API logic.
Could you please help me how would it be possible to add condition that checks bearer token of the request, or how to connect it with RainLab.Users authentication?
For example if I have an API endpoint but I would like to protect it (make it non-public), what is the best practice to do it?
Thanks @artistro08
You gave me some very good ideas.
I almost did it as you wrote, but instead of sending the API key in the URL I passed it in bearer token. I found out that it is possible to get bearer tokens from the request with bearerToken() method.
I do not know how secure it is but it will do it for now.
We’ve improved the user plugin to include built in JWT support. This advice will work when RainLab.User v2.1 is released along with October CMS v3.3.11 and above.
Here’s what is included in the readme. Hopefully it helps with this requirement:
Working with APIs
When building API endpoints using CMS pages it can be useful to use a page for handling the authentication logic. The following is a simple example that includes various API endpoints.
title = "User API Page"
url = "/api/user/:action"
[resetPassword]
[account]
[session]
verifyToken = 1
==
{% if this.param.action == 'signin' %}
{% do response(
ajaxHandler('onSignin').withVars({
token: session.token()
})
) %}
{% endif %}
{% if this.param.action == 'register' %}
{% do response(ajaxHandler('onRegister')) %}
{% endif %}
{% if this.param.action == 'logout' %}
{% do response(ajaxHandler('onLogout')) %}
{% endif %}
{% if this.param.action == 'refresh' %}
{% do response({ data: {
token: session.token()
}}) %}
{% endif %}
An API layout to verify the user can be used for other API endpoints.
Thank you very much @daft
I have made a few quick test and it works perfectly.
I am not yet familiar with JWT authentication but I was able to call the sample request via Postman.
I also tried to call request with Http client feature of Laravel as well but it did not work for some reason.
When the user is null, it means there is no session available (Laravel Http client is not a browser and does not store cookies). The token replaces the session so this is safe to ignore.
Let’s assume we have an action called “me”:
url = "/user/api/:action"
[session]
verifyToken = 1
==
{% if this.param.action == 'me' %}
{% set user = session.user %}
{% if not user %}
{% do abort(403, 'Access Denied') %}
{% endif %}
{% do response({ data: {
id: user.id,
email: user.email,
first_name: user.name,
last_name: user.surname
}}) %}
{% endif %}
Thank you for the explanation. It is clear now.
So every time I would like to call API “me” action first I have to call “signin” action to get the actual token then use this token in other API calls as bearer token.
Just one short remark:
For some reason the sample that you wrote returned empty string to me.
Instead of this: Http::post('http://vimre.test/api/user/me')->header('Authorization', "Bearer {$jwtToken}");
It works when I use this syntax: Http::withToken($jwt_token)->post('http://vimre.test/api/user/me');