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