Skip to content

Commit f6c3ed2

Browse files
committed
feat: add auth.format for formatting credentials
1 parent 8117cc2 commit f6c3ed2

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed

Diff for: HISTORY.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
unreleased
2+
==================
3+
4+
* feat: add `auth.format` for formatting credentials
5+
16
2.0.1 / 2018-09-19
27
==================
38

Diff for: README.md

+15
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ otherwise an object with `name` and `pass` properties.
3737
Parse a basic auth authorization header string. This will return an object
3838
with `name` and `pass` properties, or `undefined` if the string is invalid.
3939

40+
### auth.format(credentials)
41+
42+
Format a credentials object with `name` and `pass` properties as a basic
43+
auth authorization header string.
44+
4045
## Example
4146

4247
Pass a Node.js request object to the module export. If parsing fails
@@ -60,6 +65,16 @@ var auth = require('basic-auth')
6065
var user = auth.parse(req.getHeader('Proxy-Authorization'))
6166
```
6267

68+
A credentials object can be formatted with `auth.format` as
69+
basic auth header string.
70+
71+
```js
72+
var auth = require('basic-auth')
73+
var credentials = { name: 'foo', pass: 'bar' }
74+
var authHeader = auth.format(credentials)
75+
// => "Basic Zm9vOmJhcg=="
76+
```
77+
6378
### With vanilla node.js http server
6479

6580
```js

Diff for: index.js

+24
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ var Buffer = require('safe-buffer').Buffer
2222

2323
module.exports = auth
2424
module.exports.parse = parse
25+
module.exports.format = format
2526

2627
/**
2728
* RegExp for basic auth credentials
@@ -122,6 +123,29 @@ function parse (string) {
122123
return new Credentials(userPass[1], userPass[2])
123124
}
124125

126+
/**
127+
* Format Basic Authorization Header
128+
*
129+
* @param {Credentials} credentials
130+
* @return {string}
131+
* @public
132+
*/
133+
function format (credentials) {
134+
if (!credentials) {
135+
throw new TypeError('argument credentials is required')
136+
}
137+
138+
if (typeof credentials !== 'object') {
139+
throw new TypeError('argument credentials is required to be an object')
140+
}
141+
142+
if (typeof credentials.name !== 'string' || typeof credentials.pass !== 'string') {
143+
throw new TypeError('argument credentials is required to have name and pass properties')
144+
}
145+
146+
return 'Basic ' + Buffer.from(credentials.name + ':' + credentials.pass).toString('base64')
147+
}
148+
125149
/**
126150
* Object to represent user credentials.
127151
* @private

Diff for: test/basic-auth.js

+71
Original file line numberDiff line numberDiff line change
@@ -230,3 +230,74 @@ describe('auth.parse(string)', function () {
230230
})
231231
})
232232
})
233+
234+
describe('auth.format(credentials)', function () {
235+
describe('arguments', function () {
236+
describe('credentials', function () {
237+
it('should be required', function () {
238+
assert.throws(auth.format, /argument credentials is required/)
239+
})
240+
241+
it('should accept credentials', function () {
242+
var header = auth.format({ name: 'foo', pass: 'bar' })
243+
assert.strictEqual(header, 'Basic Zm9vOmJhcg==')
244+
})
245+
246+
it('should reject null', function () {
247+
assert.throws(auth.format.bind(null, null), /argument credentials is required/)
248+
})
249+
250+
it('should reject a number', function () {
251+
assert.throws(auth.format.bind(null, 42), /argument credentials is required/)
252+
})
253+
254+
it('should reject a string', function () {
255+
assert.throws(auth.format.bind(null, ''), /argument credentials is required/)
256+
})
257+
258+
it('should reject an object without name', function () {
259+
assert.throws(auth.format.bind(null, { pass: 'bar' }), /argument credentials is required to have name and pass properties/)
260+
})
261+
262+
it('should reject an object without pass', function () {
263+
assert.throws(auth.format.bind(null, { name: 'foo' }), /argument credentials is required to have name and pass properties/)
264+
})
265+
266+
it('should reject an object with non-string name', function () {
267+
assert.throws(auth.format.bind(null, { name: 42, pass: 'bar' }), /argument credentials is required to have name and pass properties/)
268+
})
269+
270+
it('should reject an object with non-string pass', function () {
271+
assert.throws(auth.format.bind(null, { name: 'foo', pass: 42 }), /argument credentials is required to have name and pass properties/)
272+
})
273+
})
274+
})
275+
276+
describe('with valid credentials', function () {
277+
it('should return header', function () {
278+
var header = auth.format({ name: 'foo', pass: 'bar' })
279+
assert.strictEqual(header, 'Basic Zm9vOmJhcg==')
280+
})
281+
})
282+
283+
describe('with empty password', function () {
284+
it('should return header', function () {
285+
var header = auth.format({ name: 'foo', pass: '' })
286+
assert.strictEqual(header, 'Basic Zm9vOg==')
287+
})
288+
})
289+
290+
describe('with empty userid', function () {
291+
it('should return header', function () {
292+
var header = auth.format({ name: '', pass: 'pass' })
293+
assert.strictEqual(header, 'Basic OnBhc3M=')
294+
})
295+
})
296+
297+
describe('with empty userid and pass', function () {
298+
it('should return header', function () {
299+
var header = auth.format({ name: '', pass: '' })
300+
assert.strictEqual(header, 'Basic Og==')
301+
})
302+
})
303+
})

0 commit comments

Comments
 (0)