]>
Commit | Line | Data |
---|---|---|
1 | # REST API | |
2 | ||
3 | ## Server requirements | |
4 | ||
5 | See the **[REST API documentation](http://shaarli.github.io/api-documentation/)** for a list of available endpoints and parameters. | |
6 | ||
7 | Please ensure that your server meets the requirements and is properly [configured](Server-configuration): | |
8 | ||
9 | - URL rewriting is enabled (see specific Apache and Nginx sections) | |
10 | - the server's timezone is properly defined | |
11 | - the server's clock is synchronized with [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) | |
12 | ||
13 | The host where the API client is invoked should also be synchronized with NTP, see _payload/token expiration_ | |
14 | ||
15 | ||
16 | ## Clients and examples | |
17 | ||
18 | - **[python-shaarli-client](https://github.com/shaarli/python-shaarli-client)** - the reference API client ([Documentation](http://python-shaarli-client.readthedocs.io/en/latest/)) | |
19 | - [shaarli-client](https://www.npmjs.com/package/shaarli-client) - NodeJs client ([source code](https://github.com/laBecasse/shaarli-client)) by [laBecasse](https://github.com/laBecasse) | |
20 | - [Android client example with Kotlin](https://gitlab.com/snippets/1665808) by [Braincoke](https://github.com/Braincoke) | |
21 | ||
22 | ||
23 | This example uses the [PHP cURL](http://php.net/manual/en/book.curl.php) library. | |
24 | ||
25 | ```php | |
26 | <?php | |
27 | $baseUrl = 'https://shaarli.mydomain.net'; | |
28 | $secret = 'thats_my_api_secret'; | |
29 | ||
30 | function base64url_encode($data) { | |
31 | return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); | |
32 | } | |
33 | ||
34 | function generateToken($secret) { | |
35 | $header = base64url_encode('{ | |
36 | "typ": "JWT", | |
37 | "alg": "HS512" | |
38 | }'); | |
39 | $payload = base64url_encode('{ | |
40 | "iat": '. time() .' | |
41 | }'); | |
42 | $signature = base64url_encode(hash_hmac('sha512', $header .'.'. $payload , $secret, true)); | |
43 | return $header . '.' . $payload . '.' . $signature; | |
44 | } | |
45 | ||
46 | ||
47 | function getInfo($baseUrl, $secret) { | |
48 | $token = generateToken($secret); | |
49 | $endpoint = rtrim($baseUrl, '/') . '/api/v1/info'; | |
50 | ||
51 | $headers = [ | |
52 | 'Content-Type: text/plain; charset=UTF-8', | |
53 | 'Authorization: Bearer ' . $token, | |
54 | ]; | |
55 | ||
56 | $ch = curl_init($endpoint); | |
57 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | |
58 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
59 | curl_setopt($ch, CURLOPT_AUTOREFERER, 1); | |
60 | curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); | |
61 | ||
62 | $result = curl_exec($ch); | |
63 | curl_close($ch); | |
64 | ||
65 | return $result; | |
66 | } | |
67 | ||
68 | var_dump(getInfo($baseUrl, $secret)); | |
69 | ``` | |
70 | ||
71 | ## Implementation | |
72 | ||
73 | ### Authentication | |
74 | ||
75 | - All requests to Shaarli's API must include a **JWT token** to verify their authenticity. | |
76 | - This token must be included as an HTTP header called `Authorization: Bearer <jwt token>`. | |
77 | - JWT tokens are composed by three parts, separated by a dot `.` and encoded in base64: | |
78 | ||
79 | ``` | |
80 | [header].[payload].[signature] | |
81 | ``` | |
82 | ||
83 | ##### Header | |
84 | ||
85 | Shaarli only allow one hash algorithm, so the header will always be the same: | |
86 | ||
87 | ```json | |
88 | { | |
89 | "typ": "JWT", | |
90 | "alg": "HS512" | |
91 | } | |
92 | ``` | |
93 | ||
94 | Encoded in base64, it gives: | |
95 | ||
96 | ``` | |
97 | ewogICAgICAgICJ0eXAiOiAiSldUIiwKICAgICAgICAiYWxnIjogIkhTNTEyIgogICAgfQ== | |
98 | ``` | |
99 | ||
100 | ##### Payload | |
101 | ||
102 | Token expiration: To avoid infinite token validity, JWT tokens must include their creation date in UNIX timestamp format (timezone independent - UTC) under the key `iat` (issued at) field ([1](https://tools.ietf.org/html/rfc7519#section-4.1.6)). This token will be valid during **9 minutes**. | |
103 | ||
104 | ```json | |
105 | { | |
106 | "iat": 1468663519 | |
107 | } | |
108 | ``` | |
109 | ||
110 | ##### Signature | |
111 | ||
112 | The signature authenticates the token validity. It contains the base64 of the header and the body, separated by a dot `.`, hashed in SHA512 with the API secret available in Shaarli administration page. | |
113 | ||
114 | Example signature with PHP: | |
115 | ||
116 | ```php | |
117 | $content = base64_encode($header) . '.' . base64_encode($payload); | |
118 | $signature = hash_hmac('sha512', $content, $secret); | |
119 | ``` | |
120 | ||
121 | ||
122 | ||
123 | ## Troubleshooting | |
124 | ||
125 | ### Debug mode | |
126 | ||
127 | > This should never be used in a production environment. | |
128 | ||
129 | For security reasons, authentication issues will always return an `HTTP 401` error code without any detail. | |
130 | ||
131 | It is possible to enable the debug mode in `config.json.php` | |
132 | to get the actual error message in the HTTP response body with: | |
133 | ||
134 | ```json | |
135 | { | |
136 | "dev": { | |
137 | "debug": true | |
138 | } | |
139 | } | |
140 | ``` | |
141 | ||
142 | ## References | |
143 | ||
144 | - [jwt.io](https://jwt.io) (including a list of client per language). | |
145 | - [RFC - JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) | |
146 | - [JSON Web Tokens (JWT) vs Sessions](https://float-middle.com/json-web-tokens-jwt-vs-sessions/), [HackerNews thread](https://news.ycombinator.com/item?id=11929267) | |
147 | ||
148 | ||
149 | ||
150 |