diff options
Diffstat (limited to 'doc/md/REST-API.md')
-rw-r--r-- | doc/md/REST-API.md | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/doc/md/REST-API.md b/doc/md/REST-API.md new file mode 100644 index 00000000..68a83c00 --- /dev/null +++ b/doc/md/REST-API.md | |||
@@ -0,0 +1,153 @@ | |||
1 | ## Usage and Prerequisites | ||
2 | |||
3 | See the [REST API documentation](http://shaarli.github.io/api-documentation/) | ||
4 | for a list of available endpoints and parameters. | ||
5 | |||
6 | Please ensure that your server meets the [requirements](Server-requirements) | ||
7 | 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 | ||
12 | [NTP](https://en.wikipedia.org/wiki/Network_Time_Protocol) | ||
13 | |||
14 | The host where the API client is invoked should also be synchronized with NTP, | ||
15 | see [token expiration](#payload). | ||
16 | |||
17 | ## Authentication | ||
18 | |||
19 | All requests to Shaarli's API must include a JWT token to verify their authenticity. | ||
20 | |||
21 | This token has to be included as an HTTP header called `Authentication: Bearer <jwt token>`. | ||
22 | |||
23 | JWT resources : | ||
24 | |||
25 | - [jwt.io](https://jwt.io) (including a list of client per language). | ||
26 | - RFC : https://tools.ietf.org/html/rfc7519 | ||
27 | - https://float-middle.com/json-web-tokens-jwt-vs-sessions/ | ||
28 | - HackerNews thread: https://news.ycombinator.com/item?id=11929267 | ||
29 | |||
30 | |||
31 | ### Shaarli JWT Token | ||
32 | |||
33 | JWT tokens are composed by three parts, separated by a dot `.` and encoded in base64: | ||
34 | |||
35 | ``` | ||
36 | [header].[payload].[signature] | ||
37 | ``` | ||
38 | |||
39 | #### Header | ||
40 | |||
41 | Shaarli only allow one hash algorithm, so the header will always be the same: | ||
42 | |||
43 | ```json | ||
44 | { | ||
45 | "typ": "JWT", | ||
46 | "alg": "HS512" | ||
47 | } | ||
48 | ``` | ||
49 | |||
50 | Encoded in base64, it gives: | ||
51 | |||
52 | ``` | ||
53 | ewogICAgICAgICJ0eXAiOiAiSldUIiwKICAgICAgICAiYWxnIjogIkhTNTEyIgogICAgfQ== | ||
54 | ``` | ||
55 | |||
56 | #### Payload | ||
57 | |||
58 | **Token expiration** | ||
59 | |||
60 | To avoid infinite token validity, JWT tokens must include their creation date | ||
61 | in UNIX timestamp format (timezone independent - UTC) under the key `iat` (issued at). | ||
62 | This token will be valid during **9 minutes**. | ||
63 | |||
64 | ```json | ||
65 | { | ||
66 | "iat": 1468663519 | ||
67 | } | ||
68 | ``` | ||
69 | |||
70 | See [RFC reference](https://tools.ietf.org/html/rfc7519#section-4.1.6). | ||
71 | |||
72 | |||
73 | #### Signature | ||
74 | |||
75 | The signature authenticate 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. | ||
76 | |||
77 | Signature example with PHP: | ||
78 | |||
79 | ```php | ||
80 | $content = base64_encode($header) . '.' . base64_encode($payload); | ||
81 | $signature = hash_hmac('sha512', $content, $secret); | ||
82 | ``` | ||
83 | |||
84 | |||
85 | ## Clients and examples | ||
86 | ### Android, Java, Kotlin | ||
87 | |||
88 | - [Android client example with Kotlin](https://gitlab.com/snippets/1665808) | ||
89 | by [Braincoke](https://github.com/Braincoke) | ||
90 | |||
91 | ### Javascript, NodeJS | ||
92 | |||
93 | - [shaarli-client](https://www.npmjs.com/package/shaarli-client) | ||
94 | ([source code](https://github.com/laBecasse/shaarli-client)) | ||
95 | by [laBecasse](https://github.com/laBecasse) | ||
96 | |||
97 | ### PHP | ||
98 | |||
99 | This example uses the [PHP cURL](http://php.net/manual/en/book.curl.php) library. | ||
100 | |||
101 | ```php | ||
102 | <?php | ||
103 | $baseUrl = 'https://shaarli.mydomain.net'; | ||
104 | $secret = 'thats_my_api_secret'; | ||
105 | |||
106 | function base64url_encode($data) { | ||
107 | return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); | ||
108 | } | ||
109 | |||
110 | function generateToken($secret) { | ||
111 | $header = base64url_encode('{ | ||
112 | "typ": "JWT", | ||
113 | "alg": "HS512" | ||
114 | }'); | ||
115 | $payload = base64url_encode('{ | ||
116 | "iat": '. time() .' | ||
117 | }'); | ||
118 | $signature = base64url_encode(hash_hmac('sha512', $header .'.'. $payload , $secret, true)); | ||
119 | return $header . '.' . $payload . '.' . $signature; | ||
120 | } | ||
121 | |||
122 | |||
123 | function getInfo($baseUrl, $secret) { | ||
124 | $token = generateToken($secret); | ||
125 | $endpoint = rtrim($baseUrl, '/') . '/api/v1/info'; | ||
126 | |||
127 | $headers = [ | ||
128 | 'Content-Type: text/plain; charset=UTF-8', | ||
129 | 'Authorization: Bearer ' . $token, | ||
130 | ]; | ||
131 | |||
132 | $ch = curl_init($endpoint); | ||
133 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | ||
134 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
135 | curl_setopt($ch, CURLOPT_AUTOREFERER, 1); | ||
136 | curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1); | ||
137 | |||
138 | $result = curl_exec($ch); | ||
139 | curl_close($ch); | ||
140 | |||
141 | return $result; | ||
142 | } | ||
143 | |||
144 | var_dump(getInfo($baseUrl, $secret)); | ||
145 | ``` | ||
146 | |||
147 | |||
148 | ### Python | ||
149 | |||
150 | See the reference API client: | ||
151 | |||
152 | - [Documentation](http://python-shaarli-client.readthedocs.io/en/latest/) on ReadTheDocs | ||
153 | - [python-shaarli-client](https://github.com/shaarli/python-shaarli-client) on Github | ||