Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. # express-basic-auth
  2. [![npm version](https://badge.fury.io/js/express-basic-auth.svg)](https://badge.fury.io/js/express-basic-auth)
  3. [![npm](https://img.shields.io/npm/dm/express-basic-auth.svg)]()
  4. [![CircleCI](https://circleci.com/gh/LionC/express-basic-auth/tree/master.svg?style=shield&circle-token=74f7b1557100b45259e67d2492c263e4f99365d4)](https://circleci.com/gh/LionC/express-basic-auth/tree/master)
  5. [![David](https://img.shields.io/david/strongloop/express.svg)]()
  6. ![TypeScript compatible](https://img.shields.io/badge/typescript-compatible-brightgreen.svg)
  7. [![MIT Licence](https://badges.frapsoft.com/os/mit/mit.svg?v=103)](https://opensource.org/licenses/mit-license.php)
  8. Simple plug & play HTTP basic auth middleware for Express.
  9. ## How to install
  10. Just run
  11. ```shell
  12. npm install express-basic-auth
  13. ```
  14. ## How to use
  15. The module will export a function, that you can call with an options object to
  16. get the middleware:
  17. ```js
  18. const app = require('express')()
  19. const basicAuth = require('express-basic-auth')
  20. app.use(basicAuth({
  21. users: { 'admin': 'supersecret' }
  22. }))
  23. ```
  24. The middleware will now check incoming requests to match the credentials
  25. `admin:supersecret`.
  26. The middleware will check incoming requests for a basic auth (`Authorization`)
  27. header, parse it and check if the credentials are legit. If there are any
  28. credentials, an `auth` property will be added to the request, containing
  29. an object with `user` and `password` properties, filled with the credentials,
  30. no matter if they are legit or not.
  31. **If a request is found to not be authorized**, it will respond with HTTP 401
  32. and a configurable body (default empty).
  33. ### Static Users
  34. If you simply want to check basic auth against one or multiple static credentials,
  35. you can pass those credentials in the `users` option:
  36. ```js
  37. app.use(basicAuth({
  38. users: {
  39. 'admin': 'supersecret',
  40. 'adam': 'password1234',
  41. 'eve': 'asdfghjkl',
  42. }
  43. }))
  44. ```
  45. The middleware will check incoming requests to have a basic auth header matching
  46. one of the three passed credentials.
  47. ### Custom authorization
  48. Alternatively, you can pass your own `authorizer` function, to check the credentials
  49. however you want. It will be called with a username and password and is expected to
  50. return `true` or `false` to indicate that the credentials were approved or not.
  51. When using your own `authorizer`, make sure **not to use standard string comparison (`==` / `===`)**
  52. when comparing user input with secret credentials, as that would make you vulnerable against
  53. [timing attacks](https://en.wikipedia.org/wiki/Timing_attack). Use the provided `safeCompare`
  54. function instead - always provide the user input as its first argument. Also make sure to use bitwise
  55. logic operators (`|` and `&`) instead of the standard ones (`||` and `&&`) for the same reason, as
  56. the standard ones use shortcuts.
  57. ```js
  58. app.use(basicAuth( { authorizer: myAuthorizer } ))
  59. function myAuthorizer(username, password) {
  60. const userMatches = basicAuth.safeCompare(username, 'customuser')
  61. const passwordMatches = basicAuth.safeCompare(password, 'custompassword')
  62. return userMatches & passwordMatches
  63. }
  64. ```
  65. This will authorize all requests with the credentials 'customuser:custompassword'.
  66. In an actual application you would likely look up some data instead ;-) You can do whatever you
  67. want in custom authorizers, just return `true` or `false` in the end and stay aware of timing
  68. attacks.
  69. ### Custom Async Authorization
  70. Note that the `authorizer` function above is expected to be synchronous. This is
  71. the default behavior, you can pass `authorizeAsync: true` in the options object to indicate
  72. that your authorizer is asynchronous. In this case it will be passed a callback
  73. as the third parameter, which is expected to be called by standard node convention
  74. with an error and a boolean to indicate if the credentials have been approved or not.
  75. Let's look at the same authorizer again, but this time asynchronous:
  76. ```js
  77. app.use(basicAuth({
  78. authorizer: myAsyncAuthorizer,
  79. authorizeAsync: true,
  80. }))
  81. function myAsyncAuthorizer(username, password, cb) {
  82. if (username.startsWith('A') & password.startsWith('secret'))
  83. return cb(null, true)
  84. else
  85. return cb(null, false)
  86. }
  87. ```
  88. ### Unauthorized Response Body
  89. Per default, the response body for unauthorized responses will be empty. It can
  90. be configured using the `unauthorizedResponse` option. You can either pass a
  91. static response or a function that gets passed the express request object and is
  92. expected to return the response body. If the response body is a string, it will
  93. be used as-is, otherwise it will be sent as JSON:
  94. ```js
  95. app.use(basicAuth({
  96. users: { 'Foo': 'bar' },
  97. unauthorizedResponse: getUnauthorizedResponse
  98. }))
  99. function getUnauthorizedResponse(req) {
  100. return req.auth
  101. ? ('Credentials ' + req.auth.user + ':' + req.auth.password + ' rejected')
  102. : 'No credentials provided'
  103. }
  104. ```
  105. ### Challenge
  106. Per default the middleware will not add a `WWW-Authenticate` challenge header to
  107. responses of unauthorized requests. You can enable that by adding `challenge: true`
  108. to the options object. This will cause most browsers to show a popup to enter
  109. credentials on unauthorized responses. You can set the realm (the realm
  110. identifies the system to authenticate against and can be used by clients to save
  111. credentials) of the challenge by passing a static string or a function that gets
  112. passed the request object and is expected to return the challenge:
  113. ```js
  114. app.use(basicAuth({
  115. users: { 'someuser': 'somepassword' },
  116. challenge: true,
  117. realm: 'Imb4T3st4pp',
  118. }))
  119. ```
  120. ## Try it
  121. The repository contains an `example.js` that you can run to play around and try
  122. the middleware. To use it just put it somewhere (or leave it where it is), run
  123. ```shell
  124. npm install express express-basic-auth
  125. node example.js
  126. ```
  127. This will start a small express server listening at port 8080. Just look at the file,
  128. try out the requests and play around with the options.
  129. ## TypeScript usage
  130. A declaration file is bundled with the library. You don't have to install a `@types/` package.
  131. ```typescript
  132. import * as basicAuth from 'express-basic-auth'
  133. ```
  134. :bulb: **Using `req.auth`**
  135. express-basic-auth sets `req.auth` to an object containing the authorized credentials like `{ user: 'admin', password: 'supersecret' }`.
  136. In order to use that `req.auth` property in TypeScript without an unknown property error, use covariance to downcast the request type:
  137. ```typescript
  138. app.use(basicAuth(options), (req: basicAuth.IBasicAuthedRequest, res, next) => {
  139. res.end(`Welcome ${req.auth.user} (your password is ${req.auth.password})`)
  140. next()
  141. })
  142. ```
  143. :bulb: **A note about type inference on synchronous authorizers**
  144. Due to some TypeScript's type-system limitation, the arguments' type of the synchronous authorizers are not inferred.
  145. For example, on an asynchronous authorizer, the three arguments are correctly inferred:
  146. ```typescript
  147. basicAuth({
  148. authorizeAsync: true,
  149. authorizer: (user, password, authorize) => authorize(null, password == 'secret'),
  150. })
  151. ```
  152. However, on a synchronous authorizer, you'll have to type the arguments yourself:
  153. ```typescript
  154. basicAuth({
  155. authorizer: (user: string, password: string) => (password == 'secret')
  156. })
  157. ```
  158. ## Tests
  159. The cases in the `example.js` are also used for automated testing. So if you want
  160. to contribute or just make sure that the package still works, simply run:
  161. ```shell
  162. npm test
  163. ```