Skip to content

Commit fe59b33

Browse files
committed
merging in master and resolving conflict
2 parents 2c84e13 + cca67e0 commit fe59b33

29 files changed

+1925
-640
lines changed

SUMMARY.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,36 @@
1313
* [Quick Start](getting-started/quick-start.md)
1414
* [Your First App](getting-started/your-first-app.md)
1515
* [Services](services/readme.md)
16-
* [Providers](providers/readme.md)
17-
* [REST](providers/rest.md)
18-
* [Real-Time](providers/real-time/readme.md)
19-
* [Events](providers/real-time/events.md)
20-
* [Socket.io](providers/real-time/socket-io.md)
21-
* [Primus](providers/real-time/primus.md)
16+
* [REST](providers/rest.md)
17+
* [Real-Time](providers/real-time/readme.md)
18+
* [Socket.io](providers/real-time/socket-io.md)
19+
* [Primus](providers/real-time/primus.md)
20+
* [Event Filtering](providers/real-time/event-filtering.md)
2221
* [Databases](databases/readme.md)
23-
* [Querying and Pagination](databases/querying.md)
24-
* [In Memory](databases/in_memory.md)
25-
* [NeDB](databases/nedatabases/md)
22+
* [Pagination and sorting](databases/pagination.md)
23+
* [Querying](databases/querying.md)
24+
* [Extending adapters](databases/extending.md)
25+
* [In Memory](databases/memory.md)
26+
* [NeDB](databases/nedb.md)
2627
* [Mongoose](databases/mongoose.md)
2728
* [Sequelize](databases/sequelize.md)
2829
* [KnexJS](databases/knexjs.md)
2930
* [Waterline](databases/waterline.md)
3031
* [Hooks](hooks/readme.md)
32+
* [Bundled Hooks](hooks/bundled-hooks.md)
3133
* [Middleware](middleware/readme.md)
3234
* [Express middleware](middleware/express.md)
3335
* [Versioning](versioning.md)
3436
* [Routing](routing/readme.md)
3537
* [Versioning](routing/versioning.md)
3638
* [Authentication](authentication/readme.md)
3739
* [Local (username & password)](authentication/local.md)
38-
* Oauth (Twitter, Facebook, etc)
40+
* OAuth (Twitter, Facebook, etc)
3941
* Two-Factor (MFA)
4042
* [Authorization / Access Control](authorization/readme.md)
43+
* [Bundled Auth Hooks](authorization/bundled-hooks.md)
4144
* [Front End Clients](clients/readme.md)
42-
* [API](api/readme.md)
45+
* [API Documentation](api/readme.md)
4346
* [Guides](guides/readme.md)
4447
* Creating a plugin
4548
* React and React Native
@@ -49,4 +52,3 @@
4952
* [Contributing](contributing.md)
5053
* [Changelog](changelog.md)
5154
* [License](license.md)
52-

authentication/readme.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,40 @@ The [feathers-authentication](https://github.com/feathersjs/feathers-authenticat
99

1010
* [Setting Up Local Auth](local.md) (username and password)
1111

12+
### Usage
13+
If you are using the default options, setting up JWT auth for your Feathers app is as simple as the below example. Note: You must set up the `body-parser` module before setting up `feathers-authentication`.
1214

13-
## Other Authentication Plugins
15+
```js
16+
var app = feathers()
17+
.configure(feathers.rest())
18+
.configure(feathers.socketio())
19+
.configure(hooks())
20+
.use(bodyParser.json())
21+
.use(bodyParser.urlencoded({ extended: true }))
22+
// Provide a config object to the feathers-authentication plugin
23+
.configure(feathersAuth({
24+
secret: 'feathers-rocks'
25+
}));
26+
```
27+
28+
29+
### Options
30+
31+
The following options are available:
32+
33+
- __secret__ *required* - The secret used to create encrypted tokens.
34+
- __userEndpoint__ - The api endpoint used to look up the user service. The default is `'/api/users`.
35+
- __loginEndpoint__ - The url for posting the username and password during login. The default is `/api/login`. You can also post a valid token here to receive a new one. You might use this when the current auth token is about to expire to stay logged in on the client.
36+
- __usernameField__ The database field containing the username on the user service. The default is `username`.
37+
- __passwordField__ The database field containing the password on the user service. The default is `password`.
38+
- __loginError__ - The message to return for invalid login. Default is 'Invalid login.'
39+
- __jwtOptions__ - Used to customize the configuration for the jsonwebtoken library. [See the API](https://github.com/auth0/node-jsonwebtoken)
40+
- __jwtOptions.expiresIn__ - The number of **seconds** until the token expires. Default is 36000 (10 hours).
41+
- __strategy__ - Allows you to pass a custom strategy to use for local auth. The default strategy should fit most projects.
42+
- __passport__ (default: `require('passport')`) - The passport module
43+
44+
45+
## Other Authentication Solutions
1446
Feathers is based on Express. It's likely that an auth plugin used for Express can also work for Feathers.
1547

16-
If you have an authentication method that you would like listed here, please [submit a pull request](../contributing.md).
48+
If you have an authentication solution that you would like listed here, please [submit a pull request](../contributing.md).

authorization/bundled-hooks.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Bundled Authorization Hooks
2+
3+
Implementing authorization is not automatic, but is easy to set up with the included hooks. You can also create your own hooks to handle your app's custom business logic. For more information about hooks, refer to the [chapter on hooks](hooks/readme.md).
4+
5+
The `feathers-authentication` plugin includes the following hooks to help with the authorization process.
6+
7+
## `hashPassword(passwordField)`
8+
The `hashPassword` hook will automatically hash the data coming in on the provided `passwordField`. It is intended to be used on the user service on the `create`, `update`, or `patch` methods. The default field is `password`, but you can specify another field by providing its name as a string. [source code](https://github.com/feathersjs/feathers-authentication/blob/master/src/hooks/hash-password.js)
9+
10+
## `requireAuth()`
11+
The `requireAuth` hook throws an error if there's not a logged-in user by checking for the `hook.params.user` object. It can be used on any service method. It doesn't take any arguments. [source code](https://github.com/feathersjs/feathers-authentication/blob/master/src/hooks/require-auth.js)
12+
13+
## `queryWithUserId(idProp, idOnResource)`
14+
The `queryWithUserId` hook will automatically add the user's `idProp` as a parameter in the query. This is useful when you want to only return data that belongs to the logged-in user. The name of the key in the query params will be the string provided as the `idOnResource` variable. The default `idOnResource` is `"userId"` and the default `idProp` is `"_id"`. This means that the `User._id` will be copied into `query.userId`. [source code](https://github.com/feathersjs/feathers-authentication/blob/master/src/hooks/query-with-user-id.js)
15+
16+
## `setUserId(sourceProp, destProp)`
17+
The `setUserId` is similar to the `queryWithUserId`, but works on the incoming data instead of the query params. It's useful for automatically adding the userId to any resource being created. The default `sourceProp` is `"_id"` and the default `destProp` is `"userId"`. It can be used on `create`, `update`, or `patch`. [source code](https://github.com/feathersjs/feathers-authentication/blob/master/src/hooks/set-user-id.js)
18+
19+
## `requireAdminToSetAdmin(adminField)`
20+
The `requireAdminToSetAdmin` hook prevents users from making themselves an administrator. It deletes the `adminField` from any request to modify the user, so it's meant to be used on the User service. It can be used on the `create`, `update`, or `patch` methods. [source code](https://github.com/feathersjs/feathers-authentication/blob/master/src/hooks/require-admin-to-set-admin.js)
21+
22+
## `restrictToSelf(idProp)`
23+
The `restrictToSelf` hook only allows the user to retrieve her own user data. It does this by setting up the `idProp` in the query params. It is meant to be used on the User service on either `find` or `get`. [source code](https://github.com/feathersjs/feathers-authentication/blob/master/src/hooks/restrict-to-self.js)
24+
25+
## `toLowerCase(fieldName)`
26+
The `toLowerCase` hook is useful for making sure things like email addresses and usernames are lowercased before saving them to the database. You wouldn't want, for example, "BabyGorilla" and "babygorilla" to be two different users, so normalizing them to lowercase will make keeping track of things easier. It can be used on `create`, `update`, or `patch`. [source code](https://github.com/feathersjs/feathers-authentication/blob/master/src/hooks/to-lower-case.js)

authorization/readme.md

Lines changed: 117 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
# Authorization / Access Control
22

3-
TODO: This section needs review.
3+
Once we know which user is logged in, we need to know which parts of the app they can access. This is called Authorization, and it's where hooks really come in handy.
44

5-
Once we know which user we are working with, we need to know which parts of the app they have access to. This is called Authorization, and it's where hooks really come in handy.
6-
7-
## Adding user information to requests.
5+
## Adding user information to requests
86
The `feathers-authentication` plugin, upon login, gives back an encrypted token containing information about the user. The auth plugin also includes a special middleware that decrypts any tokens coming found in the Authorization header of requests that come through the REST provider. Here's an example of that middleware:
97

108
```js
@@ -30,27 +28,123 @@ app.use(function(req, res, next) {
3028
});
3129
```
3230

33-
## User authorization
34-
Since `feathers-authentication` adds the authenticated user information to requests with valid tokens, we can check for the user info in the hook and return with an error if the user is not authorized:
31+
If the token in any request is valid, the token will be unencrypted and the payload data is set up on `req.feathers.user`. The `req.feathers` object is special because its attributes are made available inside feathers-hooks on the `hook.params` object. We will cover how you can use this data soon, but first let's talk about some guidelines for creating your `User` schema.
32+
33+
## Getting your User schema just right
34+
Since `feathers-authentication` adds the authenticated user's info to requests, we can use it to implement our app's authorization logic. This also means that the authorization logic we will be able to put in place depends completely on the data that's available in the `User` service's schema. There is one general guideline to follow:
35+
36+
> Keep your user schema simple.
37+
38+
Remember, the more information you put in your `User` schema, the larger the JWT token will get. If you have a huge token, you're adding a huge payload to *every* authenticated request. It's not only an issue of having more bytes to transfer, though. Once it arrives at the server, the token will have to be unencrypted every time, so it requires more processing power, too. Try experimenting with the payload on [jwt.io](http://jwt.io) to get an idea of the impact your schema will have.
39+
40+
The simplest `User` schema would look something like the one below.
3541

3642
```js
37-
app.service('todos').before({
38-
create: function(hook, next) {
39-
// We only allow creating todos with an authenticated user
40-
if(!hook.params.user) {
41-
return next(new Error('You need to be authenticated'));
42-
}
43-
44-
// Check if the user belongs the `admin` group
45-
var groups = hook.params.user.groups;
46-
if(groups.indexOf('admin') === -1) {
47-
// Return with an error if not
48-
return next(new Error('User is not allowed to create a new Todo'));
49-
}
50-
51-
// Otherwise just continue on to the
52-
// next hook or the service method
53-
next();
43+
{
44+
"username": "LeanAndClean"
45+
}
46+
```
47+
48+
**Pro Tip:** There could very likely be a password on your `User` schema. Read the [section on bundled auth hooks](bundled-hooks.md) to find out how to make sure passwords don't go out to the public or into the JWT token payload.
49+
50+
But suppose we want to create an app with a more-expansive `User` schema like this one:
51+
52+
```js
53+
{
54+
"username": "ChunkyMonkey",
55+
"email": "[email protected]"
56+
"country": "Canada",
57+
"city": "Alberta",
58+
"favoriteWord": "Hoser",
59+
"dateOfBirth": "4-24-1980",
60+
"friends": [
61+
"Larry",
62+
"Curly",
63+
"Moe",
64+
"Bonnie",
65+
"Clyde",
66+
"Butch Cassidy",
67+
"The Sundance Kid"
68+
]
69+
}
70+
```
71+
72+
While all of the above attributes do have something to do with the user, they're not very useful for our authorization logic. We can optimize the setup by splitting the large model into two. We'll keep the most useful or identifying attributes in the `User` schema and move everything else out to a `profile` schema. Each application will potentially have different requirements, but here's an example split.
73+
74+
```js
75+
// User schema
76+
{
77+
"username": "ChunkyMonkey",
78+
"email": "[email protected]"
79+
}
80+
81+
// Profile schema
82+
{
83+
"country": "Canada",
84+
"city": "Alberta",
85+
"favoriteWord": "Hoser",
86+
"dateOfBirth": "4-24-1980",
87+
"friends": [
88+
"Larry",
89+
"Curly",
90+
"Moe",
91+
"Bonnie",
92+
"Clyde",
93+
"Butch Cassidy",
94+
"The Sundance Kid"
95+
]
96+
}
97+
```
98+
99+
## Adapting your schema to your app
100+
101+
Your `User` schema will change based on your how your application is structured. If you're making an app that will only be used by a single person, or if all users have the same permissions, the schema can probably stay as simple as in the previous examples. However, if the specifications for your app require that some users are administrators with greater access, you will have options on how you are going to implement authorization. If your application is more complex, you may want to put administrators in an `Admin` schema and create a separate administrative app. But for smaller apps it might make sense to simply add an attribute to the `User` schema that flags certain users as administrators:
102+
103+
```js
104+
// User schema
105+
{
106+
"username": "ElJefe",
107+
"admin": true
108+
}
109+
```
110+
111+
Now you'll know when a user gets more access by checking for the `admin` attribute. Let's take a look at how to identify users and administrators by creating our first hooks.
112+
113+
## Creating an authorization hook
114+
In the example below, only a logged-in user would be able to create a todo. The other methods on the `todos` service continue to be unprotected. The `orders` service requires an authenticated user to perform any of its methods because it uses the `all` key to register the hook.
115+
116+
```js
117+
// Create a hook that requires that a user is logged in.
118+
var requireAuth = function(hook) {
119+
if(!hook.params.user) {
120+
throw new Error('You must be logged in to do that.');
121+
}
122+
};
123+
// Create a hook that requires a user who is an admin.
124+
var requireAdmin = function(hook) {
125+
if (!hook.params.user) {
126+
throw new Error('You must be logged in to do that.');
54127
}
128+
if(!hook.params.user.admin) {
129+
throw new Error('Only admins can do that.');
130+
}
131+
};
132+
133+
134+
// Must be logged in to create a todo.
135+
app.service('todos').before({
136+
create: [requireAuth]
137+
});
138+
// Must be logged in to do anything with orders.
139+
app.service('orders').before({
140+
all: [requireAuth]
141+
});
142+
// Must be a logged-in administrator to do anything with secrets.
143+
app.service('secrets').before({
144+
all: [requireAdmin]
55145
});
56146
```
147+
148+
We created two simple hooks in the above example. The `requireAuth` hook simply checks for a logged-in user at `hook.params.user` and throws an error if there's no user data. The `requireAdmin` hook is similar, but does an extra check for if the user has an `admin = true` attribute.
149+
150+
We have prepared some useful hooks for you to use in your Authorization schema. Keep reading to learn about them.

0 commit comments

Comments
 (0)