|
| 1 | + |
1 | 2 | # auth-audience |
| 3 | + |
2 | 4 | Middleware to support JWT audience role for SakuraApi servers |
3 | 5 |
|
4 | | -# Example |
5 | | -Wherever your instantiate your instance of SakuraApi: |
6 | | -``` |
7 | | -export const sapi = new SakuraApi({ |
8 | | - models: [User], |
9 | | - plugins: [ |
10 | | - // ..., |
11 | | - { |
12 | | - plugin: addAuthAudience, |
13 | | - options: { |
14 | | - excludedRoutes: [ |
15 | | - /^\/$/, |
16 | | - { |
17 | | - regex:/^\/login$/ |
18 | | - }, |
19 | | - { |
20 | | - regex:/^\/user$/, |
21 | | - method: { |
22 | | - GET: true |
23 | | - } |
24 | | - } |
25 | | - ] |
| 6 | +Include this as a plugin when instantiating `SakuraApi`. For example: |
| 7 | +``` |
| 8 | + const authAudienceOptions = { |
| 9 | + // see: IAuthAudienceOptions for all your options |
| 10 | + }; |
| 11 | + |
| 12 | + const sapi = new SakuraApi({ |
| 13 | + // ... other stuff |
| 14 | + plugins: [ |
| 15 | + { |
| 16 | + options: authAudienceOptions, |
| 17 | + order: 1, |
| 18 | + plugin: addAuthAudience |
26 | 19 | } |
| 20 | + ] |
| 21 | + }); |
| 22 | +``` |
| 23 | + |
| 24 | +# Install |
| 25 | +`npm i @sakuraapi/auth-audience` |
| 26 | + |
| 27 | + |
| 28 | +# Configuration |
| 29 | + |
| 30 | +You'll need to setup your environment (`src/config/environment.ts`, for example) with at least the following: |
| 31 | +``` |
| 32 | +modules.export = { |
| 33 | + authentication: { |
| 34 | + jwt: { |
| 35 | + audience: "audience.somedomain.somewhere", |
| 36 | + issuer: "issuer.somedomain.somewhere", |
| 37 | + key: "12345678901234567890123456789012" |
27 | 38 | } |
28 | | - // ... |
29 | | - ], |
30 | | - routables: [UserApi] |
31 | | -}); |
| 39 | + } |
| 40 | +}; |
32 | 41 | ``` |
33 | 42 |
|
34 | | -This will set the following routes as not requiring authentication to access: |
| 43 | +The `audience` is the identifier for the server on which you are implementing this plugin, it should have also been configured in your `auth-native-authority` or `auth-oauth-authority` settings. |
| 44 | + |
| 45 | +The `issuer` is the identifier of the server that's providing the JWT credentials. |
| 46 | + |
| 47 | +The key is the shared secret with the issuer. It's a 32 character key. Remember, if your issuer is supporting multiple audience servers, they don't have to share the same private keys -- in fact, you might not want them to. |
| 48 | + |
| 49 | +This shouldn't need to be stated: don't commit your production private keys to your repo. Instead, inject them during deployment. How you do this is beyond the scope of this readme. This, by the way, is why you don't provide your key via the `authOptions` above. By putting it in your config files, you're able to create a config file for production that takes an environmental variable instead of having the key hard coded. |
| 50 | + |
| 51 | +# Use |
| 52 | +`auth-audience` exports `AuthAudience`. This can be used on your `@Routable` api calsses. |
| 53 | + |
| 54 | +Some rules to keep in mind: |
| 55 | + |
| 56 | +1. Authenticators are applied from left to right (in terms of their placement in an array). |
| 57 | +1. Each route has an array of authenticators that is a defined as `[...route-level-authenticators, ...class-level-authenticators]`. |
| 58 | +1. The first authenticator to succeed stops the iteration through authenticators. |
| 59 | +1. If all authenticators fail, the first one to have failed dictates the response. |
| 60 | +1. Authenticators can be provided alone, or as an array. |
| 61 | + |
| 62 | +## Example 1: |
35 | 63 | ``` |
36 | | -/ any method |
37 | | -/login any method |
38 | | -/user GET only |
| 64 | +@Routable({ |
| 65 | + authenticators: [AuthAudience, Anonymous], |
| 66 | + baseUrl: 'someapi' |
| 67 | +}) |
| 68 | +class SomeApi {} |
39 | 69 | ``` |
| 70 | +(`Anonymous` is an authenticator exported by `@sakuraapi/api`). |
| 71 | + |
| 72 | +Example 1 subjects all `someapi` routes to `AuthAudience`. If that fails, then it subjects the request to `Anonymous` (which will never fail). If `AuthAudience` succeeds, a JWT for the user will be available on `res.locals.jwt` (or wherever you put it if you override `onAuthorized` in your options). |
| 73 | + |
| 74 | +## Example 2: |
| 75 | +``` |
| 76 | +@Routable({ |
| 77 | + authenticators: AuthAudience, |
| 78 | + baseUrl: 'someapi' |
| 79 | +}) |
| 80 | +class SomeApi {} |
| 81 | +``` |
| 82 | + |
| 83 | +Subjects all `someapi` routes to `AuthAudience`, if that fails the user will get a 401 or whatever you set in your options. |
| 84 | + |
| 85 | +## Example 3 |
| 86 | +``` |
| 87 | +@Routable({ |
| 88 | + baseUrl: 'someapi' |
| 89 | +}) |
| 90 | +class SomeApi {} |
| 91 | +``` |
| 92 | +This just lets everything through. |
| 93 | + |
| 94 | +## Example 4 |
| 95 | +``` |
| 96 | +@Routable({ |
| 97 | + baseUrl: 'someapi' |
| 98 | +}) |
| 99 | +class SomeApi { |
| 100 | + @Route({ |
| 101 | + authenticators: Anonymous |
| 102 | + method: 'get', |
| 103 | + path: 'handler1' |
| 104 | + }) |
| 105 | + handler1(res, req, next) { |
| 106 | + next(); |
| 107 | + } |
| 108 | +
|
| 109 | + @Route({ |
| 110 | + authenticators: AuthAudience |
| 111 | + method: 'get', |
| 112 | + path: 'handler2' |
| 113 | + }) |
| 114 | + handler2(res, req, next) { |
| 115 | + next(); |
| 116 | + } |
| 117 | +} |
| 118 | +``` |
| 119 | +Here, `someapi/handler1` route is Anonymous and will let anyone through. `someapi/handler2` route is subjected to `AuthAudience`. |
| 120 | + |
| 121 | +## Example 5 |
| 122 | + ``` |
| 123 | + @Routable({ |
| 124 | + authenticators: AuthAudience, |
| 125 | + baseUrl: 'someapi' |
| 126 | + }) |
| 127 | + class SomeApi { |
| 128 | + @Route({ |
| 129 | + authenticators: Anonymous |
| 130 | + method: 'get', |
| 131 | + path: 'handler1' |
| 132 | + }) |
| 133 | + handler1(res, req, next) { |
| 134 | + next(); |
| 135 | + } |
| 136 | + |
| 137 | + @Route({ |
| 138 | + method: 'get', |
| 139 | + path: 'handler2' |
| 140 | + }) |
| 141 | + handler2(res, req, next) { |
| 142 | + next(); |
| 143 | + } |
| 144 | + } |
| 145 | + ``` |
| 146 | +In the above example, all routes would be subjected to `AuthAudience`, but `someapi/handler1` would override that and let anyone through as Anonymous. |
| 147 | + |
| 148 | +In this case, route `someapi/handler1` would not have a JWT injected since Anonymous would be executed before `AuthAudience`. Be careful with your ordering. |
| 149 | + |
| 150 | +# Contributions |
| 151 | +[](https://cla-assistant.io/sakuraapi/auth-audience) |
| 152 | + |
| 153 | +* Sign the Contributor License Agreement (CLA) |
| 154 | +* Fork the project; make your contribution (don't forget to write your unit-tests); do a pull request back to develop (pull updates frequently to not fall too far behind) |
| 155 | +* Before heading off to work on something, considering collaborating first by either (1) opening an issue or (2) starting a conversation on gitter or in the Google forum that leads to back to (1) |
| 156 | +* All work should be done against an issue (https://github.com/sakuraapi/auth-audience/issues) |
| 157 | +* All contributions require unit-tests |
| 158 | +* Use the linter (`npm run lint`) to verify you comply with the style guide |
| 159 | +* Reset your changes to the docs/ directory before submitting changes - that directory is generated by TypeDoc and we only update it when we're releasing new updates. If you want to update the documentation, change the appropriate comments in the code. |
| 160 | + |
40 | 161 |
|
41 | | -Some tips: |
| 162 | +# Bug Reporting |
| 163 | +* An ideal bug report will include a PR with a unit-testing demonstrating the bug. TDBR (test driven bug reporting). :) |
| 164 | +* Feel free to open an issue before you start working on a PR to prove / demonstrate your bug report, but please close that ticket if you find that your bug was an error on your side |
42 | 165 |
|
43 | | -1. Don't forget to properly anchor your Regex (`^`, starts with), otherwise, you'll find routes like `/\//` match every request. |
44 | | -1. You can allow multiple methods when using the `{regex: //, method: {}}` approach... just make sure they're ALL CAPS and set to `true`. |
45 | | -1. If you find yourself building crazy lists of exclusions, his might not be the right plugin for you. This assumes that most of your routes are secured by a token and that there's some exceptions (like logging in and registering). |
| 166 | +# Community and Conduct |
46 | 167 |
|
47 | | -# `baseUrl` |
48 | | -If you have a `baseUrl` set on your instance of `SakuraApi`, `auth-audience` will strip it before doing comparisons. So, if your base url is `/api` and the path you want to exclude is `/api/users`, write your Regex for `/users`. |
| 168 | +Everyone should be treated with respect. Though candor is encouraged, being mean will not be tolerated. |
0 commit comments