Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
unreleased
==================

* feat: add `auth.format` for formatting credentials

2.0.1 / 2018-09-19
==================

Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ otherwise an object with `name` and `pass` properties.
Parse a basic auth authorization header string. This will return an object
with `name` and `pass` properties, or `undefined` if the string is invalid.

### auth.format(credentials)

Format a credentials object with `name` and `pass` properties as a basic
auth authorization header string.

## Example

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

A credentials object can be formatted with `auth.format` as
basic auth header string.


<!-- eslint-disable no-unused-vars, no-undef -->

```js
var auth = require('basic-auth')
var credentials = { name: 'foo', pass: 'bar' }
var authHeader = auth.format(credentials)
// => "Basic Zm9vOmJhcg=="
```

### With vanilla node.js http server

```js
Expand Down
24 changes: 24 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ var Buffer = require('safe-buffer').Buffer

module.exports = auth
module.exports.parse = parse
module.exports.format = format

/**
* RegExp for basic auth credentials
Expand Down Expand Up @@ -122,6 +123,29 @@ function parse (string) {
return new Credentials(userPass[1], userPass[2])
}

/**
* Format Basic Authorization Header
*
* @param {Credentials} credentials
* @return {string}
* @public
*/
function format (credentials) {
if (!credentials) {
throw new TypeError('argument credentials is required')
}

if (typeof credentials !== 'object') {
throw new TypeError('argument credentials is required to be an object')
}

if (typeof credentials.name !== 'string' || typeof credentials.pass !== 'string') {
throw new TypeError('argument credentials is required to have name and pass properties')
}

return 'Basic ' + Buffer.from(credentials.name + ':' + credentials.pass).toString('base64')
}

/**
* Object to represent user credentials.
* @private
Expand Down
71 changes: 71 additions & 0 deletions test/basic-auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,3 +230,74 @@ describe('auth.parse(string)', function () {
})
})
})

describe('auth.format(credentials)', function () {
describe('arguments', function () {
describe('credentials', function () {
it('should be required', function () {
assert.throws(auth.format, /argument credentials is required/)
})

it('should accept credentials', function () {
var header = auth.format({ name: 'foo', pass: 'bar' })
assert.strictEqual(header, 'Basic Zm9vOmJhcg==')
})

it('should reject null', function () {
assert.throws(auth.format.bind(null, null), /argument credentials is required/)
})

it('should reject a number', function () {
assert.throws(auth.format.bind(null, 42), /argument credentials is required/)
})

it('should reject a string', function () {
assert.throws(auth.format.bind(null, ''), /argument credentials is required/)
})

it('should reject an object without name', function () {
assert.throws(auth.format.bind(null, { pass: 'bar' }), /argument credentials is required to have name and pass properties/)
})

it('should reject an object without pass', function () {
assert.throws(auth.format.bind(null, { name: 'foo' }), /argument credentials is required to have name and pass properties/)
})

it('should reject an object with non-string name', function () {
assert.throws(auth.format.bind(null, { name: 42, pass: 'bar' }), /argument credentials is required to have name and pass properties/)
})

it('should reject an object with non-string pass', function () {
assert.throws(auth.format.bind(null, { name: 'foo', pass: 42 }), /argument credentials is required to have name and pass properties/)
})
})
})

describe('with valid credentials', function () {
it('should return header', function () {
var header = auth.format({ name: 'foo', pass: 'bar' })
assert.strictEqual(header, 'Basic Zm9vOmJhcg==')
})
})

describe('with empty password', function () {
it('should return header', function () {
var header = auth.format({ name: 'foo', pass: '' })
assert.strictEqual(header, 'Basic Zm9vOg==')
})
})

describe('with empty userid', function () {
it('should return header', function () {
var header = auth.format({ name: '', pass: 'pass' })
assert.strictEqual(header, 'Basic OnBhc3M=')
})
})

describe('with empty userid and pass', function () {
it('should return header', function () {
var header = auth.format({ name: '', pass: '' })
assert.strictEqual(header, 'Basic Og==')
})
})
})