1 | @fusion.io/authenticate
|
2 | -----------------------
|
3 |
|
4 | Better Authentication for better Geeks.
|
5 |
|
6 |
|
7 | In short, this is an authentication framework for Node.JS
|
8 |
|
9 | Much like [PassportJS](http://www.passportjs.org/). 😛
|
10 |
|
11 | # GETTING STARTED
|
12 |
|
13 | *For quick and dirty and lazy work with this package. Please check our [supported Gateways](docs/GATEWAYS.md)*
|
14 |
|
15 | To get start, please follow these steps:
|
16 |
|
17 | 1. [Installation](#installation).
|
18 | 2. [Determine the authentication Protocol(s)](#determine-the-authentication-protocols).
|
19 | 3. [Making Identity Provider(s)](#making-identity-providers).
|
20 | 4. [Register your gateway with Protocol and Identity Provider](#register-your-gateway-with-protocol-and-identity-provider).
|
21 | 5. [Guard your resources](#guard-your-resources).
|
22 |
|
23 | For further topics, please checkout:
|
24 |
|
25 | - [Some best practices about authentications](docs/BEST_PRACTICES.md).
|
26 | - [Document about making a Protocol](docs/PROTOCOLS.md#writing-custom-protocol).
|
27 | - [Our core concepts when building this package](docs/CONCEPTS_AND_DEFINITIONS.md).
|
28 |
|
29 |
|
30 | ## Installation
|
31 |
|
32 | To install this package, please run:
|
33 |
|
34 | ```javascript
|
35 | npm install --save @fusion.io/authenticate
|
36 | ```
|
37 |
|
38 | ## Determine the authentication Protocol(s)
|
39 |
|
40 | `Hey! hey! What is protocol?`
|
41 |
|
42 | *If you're asking, a Protocol is just a service that can read the user's authentication
|
43 | information (`Credential`) from your app. Just it!*
|
44 |
|
45 | There are variety protocols out there and it is hard to choose!
|
46 | But not so many that are widely accepted and adopted.
|
47 |
|
48 | So we are here to help you go shopping!
|
49 |
|
50 | - If you just want to authenticate your user by `email`/`username`/`phone number`/`whatever...` and password.
|
51 | You should use the `Local` protocol.
|
52 |
|
53 | - If you also want to let the user can authenticate and login to your application via social networks.
|
54 | Like Facebook, Google, Linkedin, ...
|
55 | Most of them are supporting `OAuth2` protocol. So it will be your choice.
|
56 |
|
57 | - If you also provide API endpoints and you want to protect that resources, we suggest that you should use
|
58 | token. So let's add `Token` into your shopping cart!
|
59 |
|
60 | This step is just it. No code! Just cheap talk! :D
|
61 |
|
62 | ## Making Identity Provider(s).
|
63 |
|
64 | `Hey! hey! What is Identity Provider?`
|
65 |
|
66 | *Again, if you're asking, an Identity Provider is just a service that translates the credential of the above step
|
67 | into user's `Identity` (or user id or something that you can use to distinguish one user to others).*
|
68 |
|
69 | Let's check your shopping cart.
|
70 |
|
71 | If you are using `Local` protocol. Your Identity Provider should look like:
|
72 |
|
73 | ```javascript
|
74 |
|
75 | class MyLocalUserProvider {
|
76 |
|
77 | async provide({username, password}) {
|
78 | // Here you can find your user
|
79 | // Do some password verification.
|
80 |
|
81 | // and the last thing is:
|
82 |
|
83 | return user.id; // Or .email .phonenumber .whatever...
|
84 | }
|
85 | }
|
86 | ```
|
87 |
|
88 | If you are using `OAuth2` protocol, your Identity Provider should look like:
|
89 |
|
90 | ```javascript
|
91 |
|
92 | class MyOAuth2kUserProvider {
|
93 |
|
94 | async provide({access_token}) {
|
95 | // Here you can use the access_token to ask
|
96 | // the related social network for the user's
|
97 | // profile and of course, user id.
|
98 |
|
99 | // and ...
|
100 | return user.id;
|
101 | }
|
102 | }
|
103 |
|
104 | ```
|
105 |
|
106 | If you are using `Token` protocol, your Identity Provider should look like:
|
107 |
|
108 | ```javascript
|
109 |
|
110 | class MyApiUserProvider {
|
111 |
|
112 | async provide({token}) {
|
113 | // Here you can use the token to find your user.
|
114 |
|
115 | // and again:
|
116 |
|
117 | return user.id;
|
118 | }
|
119 | }
|
120 |
|
121 | ```
|
122 |
|
123 | In general, your Identity provider is nothing special but a class with an `async provide(credential)` method.
|
124 |
|
125 | Where `credential` is the information that you'll get from the protocol.
|
126 |
|
127 | ## Register your gateway with Protocol and Identity Provider
|
128 |
|
129 | Now let's mixed up your Identity Provider and protocol.
|
130 |
|
131 | ```javascript
|
132 |
|
133 | const { authenticator, HeadlessLocal } = require('@fusion.io/authenticate');
|
134 |
|
135 | // or ES6:
|
136 |
|
137 | import { authenticator, HeadlessLocal } from "@fusion.io/authenticate";
|
138 |
|
139 | authenticator.gate('local', new HeadlessLocal(), MyLocalUserProvider());
|
140 | ```
|
141 |
|
142 | In the example code above, we've registered a gateway called `local` with [`HeadlessLocal`](docs/PROTOCOLS.md#headlesslocal) protocol and your `MyLocalUserProvider` identity provider.
|
143 |
|
144 | We supports 3 basic protocols for you:
|
145 |
|
146 | [`HeadlessLocal`](docs/PROTOCOLS.md#headlesslocal), [`HttpOAuth2`](docs/PROTOCOLS.md#httpoauth2) and [`HttpTokenBearer`](docs/PROTOCOLS.md#httptokenbearer)
|
147 | . You can replace the above [`HeadlessLocal`](docs/PROTOCOLS.md#headlesslocal) to any one of them.
|
148 |
|
149 | *For more usage of Protocol, please check out the [Protocols documentation](docs/PROTOCOLS.md).*
|
150 |
|
151 | You can have as many gates as you want.
|
152 | Just use the `authenticator.gate(gateName, protocol, identityProvider);` to register a new gate.
|
153 |
|
154 | ## Guard your resources
|
155 |
|
156 | Now, your gate is ready, let's authenticate your resource with your gate.
|
157 |
|
158 | ```javascript
|
159 |
|
160 | const { UnAuthenticated, Aborted } = require('@fusion.io/authenticate');
|
161 |
|
162 | // or ES6
|
163 |
|
164 | import { UnAuthenticated, Aborted } from "@fusion.io/authenticate";
|
165 |
|
166 | ...
|
167 |
|
168 | // Some where inside your code.
|
169 |
|
170 | try {
|
171 | let userIdentity = await authenticator.authenticate('local', {username: 'rikky', password: 'Won\'t tell ya!'} );
|
172 |
|
173 | // Here is a safezone. User already authenticated
|
174 | // You can perform any thing on your resource here!
|
175 |
|
176 | } catch (error) {
|
177 | if (error instanceof UnAuthenticated) {
|
178 | // Here is not a safe zone. User is unauthenticated.
|
179 | }
|
180 |
|
181 | if (error instanceof Aborted) {
|
182 | // Here is weird zone. The Protocol decided to abort
|
183 | // authentication step.
|
184 | }
|
185 |
|
186 | // Here is crazy zone. Some thing went wrong! you better throw the
|
187 | // error out for debugging.
|
188 | throw error;
|
189 | }
|
190 |
|
191 | ```
|
192 |
|
193 | ### Good news for `Koa`, `Express`, `Socket.IO` users!
|
194 |
|
195 | We love `middleware` style! If you are using above frameworks,
|
196 | you'll have a very nice place to authenticate your resources. The mighty `middleware`:
|
197 |
|
198 | ```javascript
|
199 |
|
200 | // For example, here we'll wrap the `.authenticate()` method inside a Koa middleware.
|
201 |
|
202 | const localAuthentication = async (context, next) => {
|
203 | try {
|
204 | let userIdentity = await authenticator.authenticate('local', context.request.body);
|
205 |
|
206 | context.identity = userIdentity;
|
207 | await next();
|
208 |
|
209 | } catch (error) {
|
210 | if (error instanceof Aborted) {
|
211 | return;
|
212 | }
|
213 | throw error;
|
214 | }
|
215 | }
|
216 |
|
217 |
|
218 | // So now, we can do something like:
|
219 |
|
220 |
|
221 | app.use(localAuthentication);
|
222 |
|
223 | ```
|
224 |
|
225 |
|
226 | And for your laziness, we also wrapped it. So beside [`HeadlessLocal`](docs/PROTOCOLS.md#headlesslocal), [`HttpOAuth2`](docs/PROTOCOLS.md#httpoauth2) and [`HttpTokenBearer`](docs/PROTOCOLS.md#httptokenbearer) we have
|
227 | [`ExpressLocal`](docs/PROTOCOLS.md#expresslocal),
|
228 | [`KoaLocal`](docs/PROTOCOLS.md#koalocal),
|
229 | [`SocketIOLocal`](docs/PROTOCOLS.md#socketiolocal),
|
230 | [`KoaOAuth2`](docs/PROTOCOLS.md#koaoauth2-and-expressoauth2),
|
231 | [`ExpressOAuth2`](docs/PROTOCOLS.md#koaoauth2-and-expressoauth2),
|
232 | [`KoaToken`](docs/PROTOCOLS.md#koatoken-and-express-token),
|
233 | [`ExpressToken`](docs/PROTOCOLS.md#koatoken-and-express-token),
|
234 | [`SocketIOToken`](docs/PROTOCOLS.md#socketiotoken),
|
235 | [`KoaSession`](docs/PROTOCOLS.md#koasession-and-expresssession),
|
236 | [`ExpressSession`](docs/PROTOCOLS.md#koasession-and-expresssession).
|
237 |
|
238 | These are framework specific protocols.
|
239 | It have ability to `mount` to your framework as a middleware and `authenticate` its endpoints.
|
240 |
|
241 | You can replace the above code by simple `authenticator.authenticate()` method:
|
242 |
|
243 | ```javascript
|
244 |
|
245 | // For koa:
|
246 | //
|
247 | // app or router
|
248 | app.use(authenticator.authenticate('local'));
|
249 | // Then you can get the identity by accessing `context.identity`.
|
250 |
|
251 | // For express:
|
252 | //
|
253 | // app or router
|
254 | app.use(authenticator.authenticate('local'));
|
255 | // Then you can get the identity by accessing `request.identity`.
|
256 |
|
257 | // For Socket.IO:
|
258 | //
|
259 | // socket or namespace
|
260 | socket.use(authenticator.authenticate('local'));
|
261 | // Then you can get the identity by accessing `socket.identity`.
|
262 |
|
263 | ```
|
264 |
|
265 |
|
266 | ### Good news for users don't find a suitable protocol.
|
267 |
|
268 | So if you don't think these above protocols are suitable, and you decided to write one for you.
|
269 | That's great! Now you are becoming seriously! Please check the [CUSTOM PROTOCOL](docs/PROTOCOLS.md#writing-custom-protocol) part.
|
270 |
|
271 |
|
272 | ### Tips:
|
273 |
|
274 | - **Gateway** is a unit of work that combines a protocol and an identity provider together.
|
275 | It's the building block of authentication process.
|
276 | **Authenticator** is just a service that managing gates. Just it!
|
277 | - Relationship between **Protocol** and **IdentityProvider** is many-to-many.
|
278 | **Gateway** is a pivot representing that relationship.
|
279 | - You can have many **Protocols** that sharing the same **Identity Provider** if they providing the same `Credential`.
|
280 |
|
281 | For example: *your application may support `token` authentication via web APIs.
|
282 | And you also want to support `token` authentication via WebSocket.
|
283 | But no matter what the transport layer is, they still returning a `token` as a `Credential`,
|
284 | using the same **Identity Provider** in this case will enable your ability to authenticate the same user over multiple transport layers.*
|
285 | - In reverse, you can also have many **Identity Providers** that sharing the same **Protocol** when we have more than one **Type Of User**,
|
286 | but sharing the same way of authentication (same way of providing `Credential`).
|
287 |
|
288 | For example: *your application may want to authenticate **users** and **organizations** account.
|
289 | In both cases, they will provide **email** and **password** as `Credential`.
|
290 | Using the same **Protocol** will help your code DRY by not providing 2 **Protocols** that are identical to each other.*
|
291 |
|
292 |
|
293 | # BEST PRACTICES
|
294 |
|
295 | Please checkout some [best practices](docs/BEST_PRACTICES.md) about authentication.
|
296 |
|
297 | # FOR YOUR LAZINESS:
|
298 |
|
299 | We ship some common social authentication services:
|
300 | `Facebook`,
|
301 | `Google`,
|
302 | `Instagram`,
|
303 | `Slack`,
|
304 | `GitHub`
|
305 | out of the box. So you may wants to check out [how to have the `Login via XXX` button](docs/GATEWAYS.md).
|
306 |
|
307 | # CUSTOM PROTOCOL
|
308 |
|
309 | Please checkout the [document about making a Protocol](docs/PROTOCOLS.md#writing-custom-protocol).
|
310 |
|
311 | # CONCEPTS AND DEFINITIONS
|
312 |
|
313 | Please check out [our concepts](docs/CONCEPTS_AND_DEFINITIONS.md) when building this package.
|