diff --git a/.gitignore b/.gitignore
index aab8bd5821..1a04bd9748 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,7 @@ dist/
 packages/authentication/lib
 packages/authentication-local/lib
 packages/authentication-client/lib
+packages/authentication-oauth/lib
 packages/configuration/lib
 packages/commons/lib
 packages/transport-commons/lib
diff --git a/package-lock.json b/package-lock.json
index 021f91ead1..76f008e1b6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -189,16 +189,16 @@
 			}
 		},
 		"@lerna/changed": {
-			"version": "3.13.1",
-			"resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.13.1.tgz",
-			"integrity": "sha512-BRXitEJGOkoudbxEewW7WhjkLxFD+tTk4PrYpHLyCBk63pNTWtQLRE6dc1hqwh4emwyGncoyW6RgXfLgMZgryw==",
+			"version": "3.13.2",
+			"resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.13.2.tgz",
+			"integrity": "sha512-mcmkxUMR0J4ZyRyVUrdDJl4ZsdHDgdA1xQcbdB4LZvAE/E2lNlPcEfAfbfs08VnRiqvFOqcczbzBq10hvSFg4w==",
 			"dev": true,
 			"requires": {
 				"@lerna/collect-updates": "3.13.0",
 				"@lerna/command": "3.13.1",
 				"@lerna/listable": "3.13.0",
 				"@lerna/output": "3.13.0",
-				"@lerna/version": "3.13.1"
+				"@lerna/version": "3.13.2"
 			}
 		},
 		"@lerna/check-working-tree": {
@@ -605,15 +605,16 @@
 			}
 		},
 		"@lerna/npm-publish": {
-			"version": "3.13.0",
-			"resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.13.0.tgz",
-			"integrity": "sha512-y4WO0XTaf9gNRkI7as6P2ItVDOxmYHwYto357fjybcnfXgMqEA94c3GJ++jU41j0A9vnmYC6/XxpTd9sVmH9tA==",
+			"version": "3.13.2",
+			"resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.13.2.tgz",
+			"integrity": "sha512-HMucPyEYZfom5tRJL4GsKBRi47yvSS2ynMXYxL3kO0ie+j9J7cb0Ir8NmaAMEd3uJWJVFCPuQarehyfTDZsSxg==",
 			"dev": true,
 			"requires": {
 				"@lerna/run-lifecycle": "3.13.0",
 				"figgy-pudding": "^3.5.1",
 				"fs-extra": "^7.0.0",
 				"libnpmpublish": "^1.1.1",
+				"npm-package-arg": "^6.1.0",
 				"npmlog": "^4.1.2",
 				"pify": "^3.0.0",
 				"read-package-json": "^2.0.13"
@@ -805,9 +806,9 @@
 			}
 		},
 		"@lerna/publish": {
-			"version": "3.13.1",
-			"resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.13.1.tgz",
-			"integrity": "sha512-KhCJ9UDx76HWCF03i5TD7z5lX+2yklHh5SyO8eDaLptgdLDQ0Z78lfGj3JhewHU2l46FztmqxL/ss0IkWHDL+g==",
+			"version": "3.13.2",
+			"resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.13.2.tgz",
+			"integrity": "sha512-L8iceC3Z2YJnlV3cGbfk47NSh1+iOo1tD65z+BU3IYLRpPnnSf8i6BORdKV8rECDj6kjLYvL7//2yxbHy7shhA==",
 			"dev": true,
 			"requires": {
 				"@lerna/batch-packages": "3.13.0",
@@ -819,7 +820,7 @@
 				"@lerna/log-packed": "3.13.0",
 				"@lerna/npm-conf": "3.13.0",
 				"@lerna/npm-dist-tag": "3.13.0",
-				"@lerna/npm-publish": "3.13.0",
+				"@lerna/npm-publish": "3.13.2",
 				"@lerna/output": "3.13.0",
 				"@lerna/pack-directory": "3.13.1",
 				"@lerna/prompt": "3.13.0",
@@ -827,7 +828,7 @@
 				"@lerna/run-lifecycle": "3.13.0",
 				"@lerna/run-parallel-batches": "3.13.0",
 				"@lerna/validation-error": "3.13.0",
-				"@lerna/version": "3.13.1",
+				"@lerna/version": "3.13.2",
 				"figgy-pudding": "^3.5.1",
 				"fs-extra": "^7.0.0",
 				"libnpmaccess": "^3.0.1",
@@ -964,9 +965,9 @@
 			}
 		},
 		"@lerna/version": {
-			"version": "3.13.1",
-			"resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.13.1.tgz",
-			"integrity": "sha512-WpfKc5jZBBOJ6bFS4atPJEbHSiywQ/Gcd+vrwaEGyQHWHQZnPTvhqLuq3q9fIb9sbuhH5pSY6eehhuBrKqTnjg==",
+			"version": "3.13.2",
+			"resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.13.2.tgz",
+			"integrity": "sha512-85AEn6Cx5p1VOejEd5fpTyeDCx6yejSJCgbILkx+gXhLhFg2XpFzLswMd+u71X7RAttWHvhzeKJAw4tWTXDvpQ==",
 			"dev": true,
 			"requires": {
 				"@lerna/batch-packages": "3.13.0",
@@ -1020,9 +1021,9 @@
 			"dev": true
 		},
 		"@octokit/endpoint": {
-			"version": "3.2.3",
-			"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-3.2.3.tgz",
-			"integrity": "sha512-yUPCt4vMIOclox13CUxzuKiPJIFo46b/6GhUnUTw5QySczN1L0DtSxgmIZrZV4SAb9EyAqrceoyrWoYVnfF2AA==",
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-4.0.0.tgz",
+			"integrity": "sha512-b8sptNUekjREtCTJFpOfSIL4SKh65WaakcyxWzRcSPOk5RxkZJ/S8884NGZFxZ+jCB2rDURU66pSHn14cVgWVg==",
 			"dev": true,
 			"requires": {
 				"deepmerge": "3.2.0",
@@ -1038,12 +1039,12 @@
 			"dev": true
 		},
 		"@octokit/request": {
-			"version": "2.4.2",
-			"resolved": "https://registry.npmjs.org/@octokit/request/-/request-2.4.2.tgz",
-			"integrity": "sha512-lxVlYYvwGbKSHXfbPk5vxEA8w4zHOH1wobado4a9EfsyD3Cbhuhus1w0Ye9Ro0eMubGO8kNy5d+xNFisM3Tvaw==",
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/@octokit/request/-/request-3.0.0.tgz",
+			"integrity": "sha512-DZqmbm66tq+a9FtcKrn0sjrUpi0UaZ9QPUCxxyk/4CJ2rseTMpAWRf6gCwOSUCzZcx/4XVIsDk+kz5BVdaeenA==",
 			"dev": true,
 			"requires": {
-				"@octokit/endpoint": "^3.2.0",
+				"@octokit/endpoint": "^4.0.0",
 				"deprecation": "^1.0.1",
 				"is-plain-object": "^2.0.4",
 				"node-fetch": "^2.3.0",
@@ -1052,12 +1053,12 @@
 			}
 		},
 		"@octokit/rest": {
-			"version": "16.23.2",
-			"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.23.2.tgz",
-			"integrity": "sha512-ZxiZMaCuqBG/IsbgNRVfGwYsvBb5DjHuMGjJgOrinT+/b+1j1U7PiGyRkHDJdjTGA6N/PsMC2lP2ZybX9579iA==",
+			"version": "16.24.1",
+			"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.24.1.tgz",
+			"integrity": "sha512-V2GVL+cfuwNTcZ9qtBMOR9pIftWo1AiZIiGvWNmTcIQG5mkj83ZXC+g3w5g0cVXt7Hi+mSOrD2bZ7HJOuouUNg==",
 			"dev": true,
 			"requires": {
-				"@octokit/request": "2.4.2",
+				"@octokit/request": "3.0.0",
 				"atob-lite": "^2.0.0",
 				"before-after-hook": "^1.4.0",
 				"btoa-lite": "^1.0.0",
@@ -1861,9 +1862,9 @@
 			}
 		},
 		"commander": {
-			"version": "2.19.0",
-			"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
-			"integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
+			"version": "2.20.0",
+			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+			"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
 			"dev": true
 		},
 		"commondir": {
@@ -1894,9 +1895,9 @@
 			}
 		},
 		"component-emitter": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-			"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+			"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
 			"dev": true
 		},
 		"concat-map": {
@@ -2060,9 +2061,9 @@
 			}
 		},
 		"conventional-changelog-preset-loader": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.0.2.tgz",
-			"integrity": "sha512-pBY+qnUoJPXAXXqVGwQaVmcye05xi6z231QM98wHWamGAmu/ghkBprQAwmF5bdmyobdVxiLhPY3PrCfSeUNzRQ==",
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.1.1.tgz",
+			"integrity": "sha512-K4avzGMLm5Xw0Ek/6eE3vdOXkqnpf9ydb68XYmCc16cJ99XMMbc2oaNMuPwAsxVK6CC1yA4/I90EhmWNj0Q6HA==",
 			"dev": true
 		},
 		"conventional-changelog-writer": {
@@ -2401,15 +2402,15 @@
 			}
 		},
 		"conventional-recommended-bump": {
-			"version": "4.0.4",
-			"resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-4.0.4.tgz",
-			"integrity": "sha512-9mY5Yoblq+ZMqJpBzgS+RpSq+SUfP2miOR3H/NR9drGf08WCrY9B6HAGJZEm6+ThsVP917VHAahSOjM6k1vhPg==",
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-4.1.1.tgz",
+			"integrity": "sha512-JT2vKfSP9kR18RXXf55BRY1O3AHG8FPg5btP3l7LYfcWJsiXI6MCf30DepQ98E8Qhowvgv7a8iev0J1bEDkTFA==",
 			"dev": true,
 			"requires": {
-				"concat-stream": "^1.6.0",
-				"conventional-changelog-preset-loader": "^2.0.2",
-				"conventional-commits-filter": "^2.0.1",
-				"conventional-commits-parser": "^3.0.1",
+				"concat-stream": "^2.0.0",
+				"conventional-changelog-preset-loader": "^2.1.1",
+				"conventional-commits-filter": "^2.0.2",
+				"conventional-commits-parser": "^3.0.2",
 				"git-raw-commits": "2.0.0",
 				"git-semver-tags": "^2.0.2",
 				"meow": "^4.0.0",
@@ -2433,6 +2434,43 @@
 						"quick-lru": "^1.0.0"
 					}
 				},
+				"concat-stream": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
+					"integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+					"dev": true,
+					"requires": {
+						"buffer-from": "^1.0.0",
+						"inherits": "^2.0.3",
+						"readable-stream": "^3.0.2",
+						"typedarray": "^0.0.6"
+					}
+				},
+				"conventional-commits-filter": {
+					"version": "2.0.2",
+					"resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz",
+					"integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==",
+					"dev": true,
+					"requires": {
+						"lodash.ismatch": "^4.4.0",
+						"modify-values": "^1.0.0"
+					}
+				},
+				"conventional-commits-parser": {
+					"version": "3.0.2",
+					"resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.2.tgz",
+					"integrity": "sha512-y5eqgaKR0F6xsBNVSQ/5cI5qIF3MojddSUi1vKIggRkqUTbkqFKH9P5YX/AT1BVZp9DtSzBTIkvjyVLotLsVog==",
+					"dev": true,
+					"requires": {
+						"JSONStream": "^1.0.4",
+						"is-text-path": "^1.0.0",
+						"lodash": "^4.2.1",
+						"meow": "^4.0.0",
+						"split2": "^2.0.0",
+						"through2": "^3.0.0",
+						"trim-off-newlines": "^1.0.0"
+					}
+				},
 				"find-up": {
 					"version": "2.1.0",
 					"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
@@ -2535,6 +2573,17 @@
 						"read-pkg": "^3.0.0"
 					}
 				},
+				"readable-stream": {
+					"version": "3.3.0",
+					"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz",
+					"integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==",
+					"dev": true,
+					"requires": {
+						"inherits": "^2.0.3",
+						"string_decoder": "^1.1.1",
+						"util-deprecate": "^1.0.1"
+					}
+				},
 				"redent": {
 					"version": "2.0.0",
 					"resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
@@ -2557,6 +2606,15 @@
 					"integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=",
 					"dev": true
 				},
+				"through2": {
+					"version": "3.0.1",
+					"resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
+					"integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
+					"dev": true,
+					"requires": {
+						"readable-stream": "2 || 3"
+					}
+				},
 				"trim-newlines": {
 					"version": "2.0.0",
 					"resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz",
@@ -2711,15 +2769,6 @@
 				"meow": "^3.3.0"
 			}
 		},
-		"debug": {
-			"version": "2.6.9",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-			"dev": true,
-			"requires": {
-				"ms": "2.0.0"
-			}
-		},
 		"debuglog": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz",
@@ -3057,6 +3106,15 @@
 				"to-regex": "^3.0.1"
 			},
 			"dependencies": {
+				"debug": {
+					"version": "2.6.9",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+					"dev": true,
+					"requires": {
+						"ms": "2.0.0"
+					}
+				},
 				"define-property": {
 					"version": "0.2.5",
 					"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -4244,9 +4302,9 @@
 			}
 		},
 		"handlebars": {
-			"version": "4.1.1",
-			"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz",
-			"integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==",
+			"version": "4.1.2",
+			"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
+			"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
 			"dev": true,
 			"requires": {
 				"neo-async": "^2.6.0",
@@ -4564,9 +4622,9 @@
 			}
 		},
 		"inquirer": {
-			"version": "6.2.2",
-			"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.2.tgz",
-			"integrity": "sha512-Z2rREiXA6cHRR9KBOarR3WuLlFzlIfAEIiB45ll5SSadMg7WqOh1MKEjjndfuH5ewXdixWCxqnVfGOQzPeiztA==",
+			"version": "6.3.1",
+			"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.3.1.tgz",
+			"integrity": "sha512-MmL624rfkFt4TG9y/Jvmt8vdmOo836U7Y0Hxr2aFk3RelZEGX4Igk0KabWrcaaZaTv9uzglOqWh1Vly+FAWAXA==",
 			"dev": true,
 			"requires": {
 				"ansi-escapes": "^3.2.0",
@@ -4580,7 +4638,7 @@
 				"run-async": "^2.2.0",
 				"rxjs": "^6.4.0",
 				"string-width": "^2.1.0",
-				"strip-ansi": "^5.0.0",
+				"strip-ansi": "^5.1.0",
 				"through": "^2.3.6"
 			},
 			"dependencies": {
@@ -5158,14 +5216,14 @@
 			}
 		},
 		"lerna": {
-			"version": "3.13.1",
-			"resolved": "https://registry.npmjs.org/lerna/-/lerna-3.13.1.tgz",
-			"integrity": "sha512-7kSz8LLozVsoUNTJzJzy+b8TnV9YdviR2Ee2PwGZSlVw3T1Rn7kOAPZjEi+3IWnOPC96zMPHVmjCmzQ4uubalw==",
+			"version": "3.13.2",
+			"resolved": "https://registry.npmjs.org/lerna/-/lerna-3.13.2.tgz",
+			"integrity": "sha512-2iliiFVAMNqaKsVSJ90p49dur93d5RlktotAJNp+uuHsCuIIAvwceqmSgDQCmWu4GkgAom+5uy//KV6F9t8fLA==",
 			"dev": true,
 			"requires": {
 				"@lerna/add": "3.13.1",
 				"@lerna/bootstrap": "3.13.1",
-				"@lerna/changed": "3.13.1",
+				"@lerna/changed": "3.13.2",
 				"@lerna/clean": "3.13.1",
 				"@lerna/cli": "3.13.0",
 				"@lerna/create": "3.13.1",
@@ -5175,9 +5233,9 @@
 				"@lerna/init": "3.13.1",
 				"@lerna/link": "3.13.1",
 				"@lerna/list": "3.13.1",
-				"@lerna/publish": "3.13.1",
+				"@lerna/publish": "3.13.2",
 				"@lerna/run": "3.13.1",
-				"@lerna/version": "3.13.1",
+				"@lerna/version": "3.13.2",
 				"import-local": "^1.0.0",
 				"npmlog": "^4.1.2"
 			}
@@ -5318,6 +5376,12 @@
 			"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
 			"dev": true
 		},
+		"lodash.ismatch": {
+			"version": "4.4.0",
+			"resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
+			"integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=",
+			"dev": true
+		},
 		"lodash.set": {
 			"version": "4.3.2",
 			"resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz",
@@ -6750,12 +6814,6 @@
 			"integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=",
 			"dev": true
 		},
-		"qs": {
-			"version": "6.5.2",
-			"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-			"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
-			"dev": true
-		},
 		"quick-lru": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
@@ -6955,6 +7013,14 @@
 				"tough-cookie": "~2.4.3",
 				"tunnel-agent": "^0.6.0",
 				"uuid": "^3.3.2"
+			},
+			"dependencies": {
+				"qs": {
+					"version": "6.5.2",
+					"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+					"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+					"dev": true
+				}
 			}
 		},
 		"requestretry": {
@@ -7261,6 +7327,15 @@
 				"use": "^3.1.0"
 			},
 			"dependencies": {
+				"debug": {
+					"version": "2.6.9",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+					"dev": true,
+					"requires": {
+						"ms": "2.0.0"
+					}
+				},
 				"define-property": {
 					"version": "0.2.5",
 					"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -8005,13 +8080,13 @@
 			"dev": true
 		},
 		"uglify-js": {
-			"version": "3.5.3",
-			"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.3.tgz",
-			"integrity": "sha512-rIQPT2UMDnk4jRX+w4WO84/pebU2jiLsjgIyrCktYgSvx28enOE3iYQMr+BD1rHiitWnDmpu0cY/LfIEpKcjcw==",
+			"version": "3.5.4",
+			"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.4.tgz",
+			"integrity": "sha512-GpKo28q/7Bm5BcX9vOu4S46FwisbPbAmkkqPnGIpKvKTM96I85N6XHQV+k4I6FA2wxgLhcsSyHoNhzucwCflvA==",
 			"dev": true,
 			"optional": true,
 			"requires": {
-				"commander": "~2.19.0",
+				"commander": "~2.20.0",
 				"source-map": "~0.6.1"
 			},
 			"dependencies": {
diff --git a/packages/authentication-client/test/integration/fixture.ts b/packages/authentication-client/test/integration/fixture.ts
index acb2ca1371..5ac106f26b 100644
--- a/packages/authentication-client/test/integration/fixture.ts
+++ b/packages/authentication-client/test/integration/fixture.ts
@@ -14,6 +14,7 @@ export default (app: Application) => {
     entity: 'user',
     service: 'users',
     secret: 'supersecret',
+    httpStrategies: [ 'jwt' ],
     jwtStrategies: [ 'local', 'jwt' ],
     local: {
       usernameField: 'email',
diff --git a/packages/authentication-local/test/fixture.js b/packages/authentication-local/test/fixture.js
index 24e9e2c606..bff7576347 100644
--- a/packages/authentication-local/test/fixture.js
+++ b/packages/authentication-local/test/fixture.js
@@ -13,6 +13,7 @@ module.exports = (app = feathers()) => {
     service: 'users',
     secret: 'supersecret',
     jwtStrategies: [ 'local', 'jwt' ],
+    httpStrategies: [ 'jwt' ],
     local: {
       usernameField: 'email',
       passwordField: 'password'
diff --git a/packages/authentication-oauth/.npmignore b/packages/authentication-oauth/.npmignore
new file mode 100644
index 0000000000..d7819044b6
--- /dev/null
+++ b/packages/authentication-oauth/.npmignore
@@ -0,0 +1,3 @@
+test/
+src/
+tsconfig.json
diff --git a/packages/authentication-oauth/CHANGELOG.md b/packages/authentication-oauth/CHANGELOG.md
new file mode 100644
index 0000000000..e9fb6ecf59
--- /dev/null
+++ b/packages/authentication-oauth/CHANGELOG.md
@@ -0,0 +1,4 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
\ No newline at end of file
diff --git a/packages/authentication-oauth/LICENSE b/packages/authentication-oauth/LICENSE
new file mode 100644
index 0000000000..25f2251eae
--- /dev/null
+++ b/packages/authentication-oauth/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 Feathers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/authentication-oauth/README.md b/packages/authentication-oauth/README.md
new file mode 100644
index 0000000000..991e9d22f1
--- /dev/null
+++ b/packages/authentication-oauth/README.md
@@ -0,0 +1,13 @@
+# @feathersjs/authentication-oauth
+
+[![Build Status](https://travis-ci.org/feathersjs/feathers.png?branch=master)](https://travis-ci.org/feathersjs/feathers)
+[![Dependency Status](https://img.shields.io/david/feathersjs/feathers.svg?style=flat-square&path=packages/authentication-oauth)](https://david-dm.org/feathersjs/feathers?path=packages/authentication-oauth)
+[![Download Status](https://img.shields.io/npm/dm/@feathersjs/authentication-oauth.svg?style=flat-square)](https://www.npmjs.com/package/@feathersjs/authentication-oauth)
+
+> OAuth 1 and 2 authentication for Feathers. Powered by Grant.
+
+## Installation
+
+```
+npm install @feathersjs/authentication-oauth --save
+```
diff --git a/packages/authentication-oauth/package.json b/packages/authentication-oauth/package.json
new file mode 100644
index 0000000000..b230087422
--- /dev/null
+++ b/packages/authentication-oauth/package.json
@@ -0,0 +1,64 @@
+{
+  "name": "@feathersjs/authentication-oauth",
+  "description": "oAuth 1 and 2 authentication for Feathers. Powered by Grant.",
+  "version": "0.0.1",
+  "homepage": "https://feathersjs.com",
+  "main": "lib/",
+  "keywords": [
+    "feathers",
+    "feathers-plugin"
+  ],
+  "license": "MIT",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/feathersjs/feathers.git"
+  },
+  "author": {
+    "name": "Feathers contributors",
+    "email": "hello@feathersjs.com",
+    "url": "https://feathersjs.com"
+  },
+  "contributors": [],
+  "bugs": {
+    "url": "https://github.com/feathersjs/feathers/issues"
+  },
+  "engines": {
+    "node": ">= 6"
+  },
+  "scripts": {
+    "start": "ts-node test/app",
+    "prepublish": "npm run compile",
+    "compile": "shx rm -rf lib/ && tsc",
+    "test": "mocha --opts ../../mocha.ts.opts --recursive test/**.test.ts test/**/*.test.ts"
+  },
+  "directories": {
+    "lib": "lib"
+  },
+  "publishConfig": {
+    "access": "public"
+  },
+  "dependencies": {
+    "@feathersjs/authentication": "^2.1.16",
+    "@feathersjs/errors": "^3.3.6",
+    "@feathersjs/express": "^1.3.1",
+    "debug": "^4.1.1",
+    "express-session": "^1.15.6",
+    "grant": "^4.5.0",
+    "grant-profile": "^0.0.3",
+    "lodash": "^4.17.11"
+  },
+  "devDependencies": {
+    "@feathersjs/feathers": "^3.3.1",
+    "@types/debug": "^4.1.3",
+    "@types/express": "^4.16.1",
+    "@types/express-session": "^1.15.12",
+    "@types/lodash": "^4.14.123",
+    "@types/mocha": "^5.2.6",
+    "@types/node": "^11.13.0",
+    "axios": "^0.18.0",
+    "mocha": "^6.0.2",
+    "shx": "^0.3.2",
+    "ts-node": "^8.0.3",
+    "typescript": "^3.4.2"
+  }
+}
diff --git a/packages/authentication-oauth/src/express.ts b/packages/authentication-oauth/src/express.ts
new file mode 100644
index 0000000000..a59bd69ef7
--- /dev/null
+++ b/packages/authentication-oauth/src/express.ts
@@ -0,0 +1,107 @@
+// @ts-ignore
+import { express as grantExpress } from 'grant';
+import Debug from 'debug';
+import session from 'express-session';
+import querystring from 'querystring';
+import { Application } from '@feathersjs/feathers';
+import { AuthenticationService, AuthenticationResult } from '@feathersjs/authentication';
+import {
+  Application as ExpressApplication,
+  original as express
+} from '@feathersjs/express';
+import { OauthSetupSettings } from './utils';
+
+const grant = grantExpress();
+const debug = Debug('@feathersjs/authentication-oauth/express');
+
+export default (options: OauthSetupSettings) => {
+  return (feathersApp: Application) => {
+    const { path, authService, linkStrategy } = options;
+    const app = feathersApp as ExpressApplication;
+    const config = app.get('grant');
+    const secret = Math.random().toString(36).substring(7);
+
+    if (!config) {
+      debug('No grant configuration found, skipping Express oAuth setup');
+      return;
+    }
+
+    const grantApp = grant(config);
+    const authApp = express();
+
+    authApp.use(session({
+      secret,
+      resave: true,
+      saveUninitialized: true
+    }));
+
+    authApp.get('/:name', (req, res) => {
+      const { name } = req.params;
+      const { feathers_token, ...query } = req.query;
+      const qs = querystring.stringify(query);
+
+      if (feathers_token) {
+        debug(`Got feathers_token query parameter to link accounts`, feathers_token);
+        req.session.accessToken = feathers_token;
+      }
+
+      const redirect = `${path}/connect/${name}${qs.length ? '?' + qs : ''}`;
+
+      debug(`Starting ${name} oAuth flow, redirecting to ${redirect}`);
+
+      res.redirect(redirect);
+    });
+
+    authApp.get('/:name/authenticate', async (req, res, next) => {
+      const { name } = req.params;
+      const { accessToken, grant } = req.session;
+      const service: AuthenticationService = app.service(authService);
+      const sendResponse = async (data: AuthenticationResult|Error) => {
+        const redirect = await options.getRedirect(service, data);
+
+        if (redirect !== null) {
+          res.redirect(redirect);
+        } else if (data instanceof Error) {
+          next(data);
+        } else {
+          res.json(data);
+        }
+      };
+
+      try {
+        const payload = config.defaults.transport === 'session' ?
+          grant.response : req.query;
+
+        const params = {
+          provider: 'rest',
+          jwtStrategies: [ name ],
+          authentication: accessToken ? {
+            strategy: linkStrategy,
+            accessToken
+          } : null
+        };
+
+        const authentication = {
+          strategy: name,
+          ...payload
+        };
+
+        debug(`Calling ${authService}.create authentication with strategy ${name}`);
+
+        const authResult = await service.create(authentication, params);
+
+        debug('Successful oAuth authentication, sending response');
+
+        await sendResponse(authResult);
+      } catch (error) {
+        debug('Received oAuth authentication error', error);
+        sendResponse(error);
+      }
+    });
+
+    authApp.use(grantApp);
+
+    app.set('grant', grantApp.config);
+    app.use(path, authApp);
+  };
+};
diff --git a/packages/authentication-oauth/src/index.ts b/packages/authentication-oauth/src/index.ts
new file mode 100644
index 0000000000..0e928c4ab7
--- /dev/null
+++ b/packages/authentication-oauth/src/index.ts
@@ -0,0 +1,57 @@
+import Debug from 'debug';
+import { merge, each, omit } from 'lodash';
+import { Application } from '@feathersjs/feathers';
+import { AuthenticationService } from '@feathersjs/authentication';
+import { OAuthStrategy, OAuthProfile } from './strategy';
+import { default as setupExpress } from './express';
+import { OauthSetupSettings, getDefaultSettings } from './utils';
+
+const debug = Debug('@feathersjs/authentication-oauth');
+
+export { OauthSetupSettings, OAuthStrategy, OAuthProfile };
+
+export const setup = (options: OauthSetupSettings) => (app: Application) => {
+  const path = options.authService;
+  const service: AuthenticationService = app.service(path);
+
+  if (!service) {
+    throw new Error(`'${path}' authentication service must exist before registering @feathersjs/authentication-oauth`);
+  }
+
+  const { oauth } = service.configuration;
+
+  if (!oauth) {
+    debug(`No oauth configuration found at '${path}'. Skipping oAuth setup.`);
+    return;
+  }
+
+  const { strategyNames } = service;
+  const grant = merge({
+    defaults: {
+      host: `${app.get('host')}:${app.get('port')}`,
+      path: '/auth',
+      protocol: app.get('env') === 'production' ? 'https' : 'http',
+      transport: 'session'
+    }
+  }, omit(oauth, 'redirect'));
+
+  each(grant, (value, key) => {
+    if (key !== 'defaults') {
+      value.callback = value.callback || `/auth/${key}/authenticate`;
+
+      if (!strategyNames.includes(key)) {
+        debug(`Registering oAuth default strategy for '${key}'`);
+        service.register(key, new OAuthStrategy());
+      }
+    }
+  });
+
+  app.set('grant', grant);
+};
+
+export const express = (settings: OauthSetupSettings = {}) => (app: Application) => {
+  const options = getDefaultSettings(app, settings);
+
+  app.configure(setup(options));
+  app.configure(setupExpress(options));
+};
diff --git a/packages/authentication-oauth/src/strategy.ts b/packages/authentication-oauth/src/strategy.ts
new file mode 100644
index 0000000000..681d5c7926
--- /dev/null
+++ b/packages/authentication-oauth/src/strategy.ts
@@ -0,0 +1,120 @@
+// @ts-ignore
+import getProfile from 'grant-profile/lib/client';
+import Debug from 'debug';
+import {
+  AuthenticationRequest, AuthenticationBaseStrategy
+} from '@feathersjs/authentication';
+import { Params } from '@feathersjs/feathers';
+import { NotAuthenticated } from '@feathersjs/errors';
+
+const debug = Debug('@feathersjs/authentication-oauth/strategy');
+
+export interface OAuthProfile {
+  id?: string|number;
+  [key: string]: any;
+}
+
+export class OAuthStrategy extends AuthenticationBaseStrategy {
+  get configuration () {
+    const { entity, service, entityId } = this.authentication.configuration;
+
+    return {
+      entity,
+      service,
+      entityId,
+      ...super.configuration
+    };
+  }
+
+  get entityId (): string {
+    return this.configuration.entityId || this.entityService.id;
+  }
+
+  /* istanbul ignore next */
+  async getProfile (data: AuthenticationRequest, _params: Params) {
+    const config = this.app.get('grant');
+    const provider = config[data.strategy];
+
+    debug('getProfile of oAuth profile from grant-profile with', data);
+
+    return getProfile(provider, data);
+  }
+
+  async getCurrentEntity (params: Params) {
+    const { authentication } = params;
+    const { entity } = this.configuration;
+
+    if (authentication && authentication.strategy) {
+      debug('getCurrentEntity with authentication', authentication);
+
+      const { strategy } = authentication;
+      const authResult = await this.authentication
+        .authenticate(authentication, params, strategy);
+
+      return authResult[entity] || null;
+    }
+
+    return null;
+  }
+
+  async findEntity (profile: OAuthProfile, params: Params) {
+    const query = {
+      [`${this.name}Id`]: profile.id
+    };
+
+    debug('findEntity with query', query);
+
+    const result = await this.entityService.find({
+      ...params,
+      query
+    });
+    const [ entity = null ] = result.data ? result.data : result;
+
+    debug('findEntity returning', entity);
+
+    return entity;
+  }
+
+  async createEntity (profile: OAuthProfile, params: Params) {
+    const data = {
+      [`${this.name}Id`]: profile.id
+    };
+
+    debug('createEntity with data', data);
+
+    return this.entityService.create(data, params);
+  }
+
+  async updateEntity (entity: any, profile: OAuthProfile, params: Params) {
+    const id = entity[this.entityId];
+    const data = {
+      [`${this.name}Id`]: profile.id
+    };
+
+    debug(`updateEntity with id ${id} and data`, data);
+
+    return this.entityService.patch(id, data, params);
+  }
+
+  async authenticate (authentication: AuthenticationRequest, params: Params) {
+    if (authentication.strategy !== this.name) {
+      throw new NotAuthenticated('Not authenticated');
+    }
+
+    const entity: string = this.configuration.entity;
+    const profile = await this.getProfile(authentication, params);
+    const existingEntity = await this.findEntity(profile, params)
+      || await this.getCurrentEntity(params);
+
+    debug(`authenticate with (existing) entity`, existingEntity);
+
+    const authEntity = existingEntity === null
+      ? await this.createEntity(profile, params)
+      : await this.updateEntity(existingEntity, profile, params);
+
+    return {
+      authentication: { strategy: this.name },
+      [entity]: authEntity
+    };
+  }
+}
diff --git a/packages/authentication-oauth/src/utils.ts b/packages/authentication-oauth/src/utils.ts
new file mode 100644
index 0000000000..04bda995d0
--- /dev/null
+++ b/packages/authentication-oauth/src/utils.ts
@@ -0,0 +1,40 @@
+import querystring from 'querystring';
+import { Application } from '@feathersjs/feathers';
+import { AuthenticationService, AuthenticationResult } from '@feathersjs/authentication';
+
+export interface OauthSetupSettings {
+  path?: string;
+  authService?: string;
+  linkStrategy?: string;
+  getRedirect? (service: AuthenticationService, data: AuthenticationResult|Error): Promise<string>;
+}
+
+export const getRedirect = async (service: AuthenticationService, data: AuthenticationResult|Error) => {
+  const { redirect } = service.configuration.oauth;
+
+  if (!redirect) {
+    return null;
+  }
+
+  const separator = redirect.endsWith('?') ? '' : '#';
+  const authResult: AuthenticationResult = data;
+  const query = authResult.accessToken ? {
+    access_token: authResult.accessToken
+  } : {
+    error: data.message || 'OAuth Authentication not successful'
+  };
+
+  return redirect + separator + querystring.stringify(query);
+};
+
+export const getDefaultSettings = (app: Application, other?: OauthSetupSettings) => {
+  const defaults: OauthSetupSettings = {
+    path: '/auth',
+    authService: app.get('defaultAuthentication'),
+    linkStrategy: 'jwt',
+    getRedirect,
+    ...other
+  };
+
+  return defaults;
+};
diff --git a/packages/authentication-oauth/test/express.test.ts b/packages/authentication-oauth/test/express.test.ts
new file mode 100644
index 0000000000..afb03682ab
--- /dev/null
+++ b/packages/authentication-oauth/test/express.test.ts
@@ -0,0 +1,50 @@
+import { strict as assert } from 'assert';
+import { Server } from 'http';
+import axios from 'axios';
+import { app } from './fixture';
+
+describe('@feathersjs/authentication-oauth/express', () => {
+  let server: Server;
+
+  before(async () => {
+    server = app.listen(9876);
+
+    await new Promise(resolve => server.once('listening', () => resolve()));
+  });
+
+  after(() => server.close());
+
+  it('auth/test', async () => {
+    axios.get('http://localhost:9876/auth/test?feathers_token=testing');
+  });
+
+  it('auth/test with query', async () => {
+    axios.get('http://localhost:9876/auth/test?other=test');
+  });
+
+  it('auth/test/authenticate', async () => {
+    const { data } = await axios.get('http://localhost:9876/auth/test/authenticate?id=expressTest');
+
+    assert.ok(data.accessToken);
+    assert.equal(data.user.testId, 'expressTest');
+  });
+
+  it('auth/test/authenticate with redirect', async () => {
+    app.get('authentication').oauth.redirect = '/';
+
+    try {
+      await axios.get('http://localhost:9876/auth/test/authenticate');
+    } catch (error) {
+      assert.ok(/Cannot GET/.test(error.response.data));
+      delete app.get('authentication').oauth.redirect;
+    }
+  });
+
+  it('auth/test/authenticate with error', async () => {
+    try {
+      await axios.get('http://localhost:9876/auth/test/authenticate');
+    } catch (error) {
+      assert.equal(error.response.data.message, 'Data needs an id');
+    }
+  });
+});
diff --git a/packages/authentication-oauth/test/fixture.ts b/packages/authentication-oauth/test/fixture.ts
new file mode 100644
index 0000000000..bffc920c85
--- /dev/null
+++ b/packages/authentication-oauth/test/fixture.ts
@@ -0,0 +1,55 @@
+import feathers, { Params } from '@feathersjs/feathers';
+import express, { rest, errorHandler } from '@feathersjs/express';
+import { AuthenticationService, JWTStrategy, AuthenticationRequest } from '@feathersjs/authentication';
+import { express as oauth, OAuthStrategy } from '../src';
+
+// @ts-ignore
+import memory from 'feathers-memory';
+
+export class TestOAuthStrategy extends OAuthStrategy {
+  async getProfile (data: AuthenticationRequest, _params: Params) {
+    if (!data.id) {
+      throw new Error('Data needs an id');
+    }
+
+    return data;
+  }
+}
+
+const port = 3000;
+const app = express(feathers());
+const auth = new AuthenticationService(app);
+
+auth.register('jwt', new JWTStrategy());
+auth.register('test', new TestOAuthStrategy());
+
+app.configure(rest());
+app.set('host', '127.0.0.1');
+app.set('port', port);
+app.set('authentication', {
+  secret: 'supersecret',
+  entity: 'user',
+  service: 'users',
+  httpStrategies: [ 'jwt' ],
+  oauth: {
+    defaults: {
+      transport: 'query'
+    },
+    test: {
+      key: 'some-key',
+      secret: 'a secret secret'
+    },
+    twitter: {
+      key: 'twitter key',
+      secret: 'some secret'
+    }
+  }
+});
+
+app.use('/authentication', auth);
+app.use('/users', memory());
+
+app.configure(oauth());
+app.use(errorHandler({ logger: null }));
+
+export { app };
diff --git a/packages/authentication-oauth/test/index.test.ts b/packages/authentication-oauth/test/index.test.ts
new file mode 100644
index 0000000000..e03b284d43
--- /dev/null
+++ b/packages/authentication-oauth/test/index.test.ts
@@ -0,0 +1,29 @@
+import { strict as assert } from 'assert';
+import feathers from '@feathersjs/feathers';
+import { setup, express } from '../src';
+import { AuthenticationService } from '@feathersjs/authentication/lib';
+
+describe('@feathersjs/authentication-oauth', () => {
+  describe('setup', () => {
+    it('errors when service does not exist', () => {
+      const app = feathers();
+
+      try {
+        app.configure(setup({ authService: 'something' }));
+        assert.fail('Should never get here');
+      } catch (error) {
+        assert.equal(error.message,
+          `'something' authentication service must exist before registering @feathersjs/authentication-oauth`
+        );
+      }
+    });
+
+    it('errors when service does not exist', () => {
+      const app = feathers();
+
+      app.use('/authentication', new AuthenticationService(app));
+
+      app.configure(express());
+    });
+  });
+});
diff --git a/packages/authentication-oauth/test/strategy.test.ts b/packages/authentication-oauth/test/strategy.test.ts
new file mode 100644
index 0000000000..23e0e1a59d
--- /dev/null
+++ b/packages/authentication-oauth/test/strategy.test.ts
@@ -0,0 +1,87 @@
+import { strict as assert } from 'assert';
+import { app, TestOAuthStrategy } from './fixture';
+import { AuthenticationService } from '@feathersjs/authentication/lib';
+
+describe('@feathersjs/authentication-oauth/strategy', () => {
+  const authService: AuthenticationService = app.service('authentication');
+  const [strategy] = authService.getStrategies('test') as TestOAuthStrategy[];
+
+  it('initializes, has .entityId and configuration', () => {
+    assert.ok(strategy);
+    assert.strictEqual(strategy.entityId, 'id');
+    assert.ok(strategy.configuration.entity);
+  });
+
+  it('getProfile', async () => {
+    const data = { id: 'getProfileTest' };
+    const profile = await strategy.getProfile(data, {});
+
+    assert.deepEqual(profile, data);
+  });
+
+  describe('authenticate', () => {
+    it('errors when strategy is not set', async () => {
+      try {
+        await strategy.authenticate({
+          id: 'newEntity'
+        }, {});
+        assert.fail('Should never get here');
+      } catch (error) {
+        assert.equal(error.name, 'NotAuthenticated');
+        assert.equal(error.message, 'Not authenticated');
+      }
+    });
+
+    it('with new user', async () => {
+      const authResult = await strategy.authenticate({
+        strategy: 'test',
+        id: 'newEntity'
+      }, {});
+
+      assert.deepEqual(authResult, {
+        authentication: { strategy: 'test' },
+        user: { testId: 'newEntity', id: authResult.user.id }
+      });
+    });
+
+    it('with existing user and already linked strategy', async () => {
+      const existingUser = await app.service('users').create({
+        testId: 'existingEntity',
+        name: 'David'
+      });
+      const authResult = await strategy.authenticate({
+        strategy: 'test',
+        id: 'existingEntity'
+      }, {});
+
+      assert.deepEqual(authResult, {
+        authentication: { strategy: 'test' },
+        user: existingUser
+      });
+    });
+
+    it('links user with existing authentication', async () => {
+      const user = await app.service('users').create({
+        name: 'David'
+      });
+      const jwt = await authService.createJWT({}, {
+        subject: `${user.id}`
+      });
+
+      const authResult = await strategy.authenticate({
+        strategy: 'test',
+        id: 'linkedEntity'
+      }, {
+        authentication: {
+          strategy: 'jwt',
+          accessToken: jwt
+        }
+      });
+
+      assert.deepEqual(authResult, {
+        authentication: { strategy: 'test' },
+        user: { id: user.id, name: user.name, testId: 'linkedEntity' }
+      });
+    });
+  });
+});
diff --git a/packages/authentication-oauth/test/utils.test.ts b/packages/authentication-oauth/test/utils.test.ts
new file mode 100644
index 0000000000..edd03a982d
--- /dev/null
+++ b/packages/authentication-oauth/test/utils.test.ts
@@ -0,0 +1,39 @@
+import { strict as assert } from 'assert';
+import { getRedirect, getDefaultSettings } from '../src/utils';
+import { app } from './fixture';
+import { AuthenticationService } from '@feathersjs/authentication/lib';
+
+describe('@feathersjs/authentication-oauth/utils', () => {
+  it('getRedirect', async () => {
+    const service: AuthenticationService = app.service('authentication');
+
+    app.get('authentication').oauth.redirect = '/home';
+
+    let redirect = await getRedirect(service, { accessToken: 'testing' });
+    assert.equal(redirect, '/home#access_token=testing');
+
+    redirect = await getRedirect(service, { message: 'something went wrong' });
+    assert.equal(redirect, '/home#error=something%20went%20wrong');
+
+    redirect = await getRedirect(service, {});
+    assert.equal(redirect, '/home#error=OAuth%20Authentication%20not%20successful');
+
+    app.get('authentication').oauth.redirect = '/home?';
+
+    redirect = await getRedirect(service, { accessToken: 'testing' });
+    assert.equal(redirect, '/home?access_token=testing');
+
+    delete app.get('authentication').oauth.redirect;
+
+    redirect = await getRedirect(service, { accessToken: 'testing' });
+    assert.equal(redirect, null);
+  });
+
+  it('getDefaultSettings', () => {
+    const settings = getDefaultSettings(app);
+
+    assert.equal(settings.path, '/auth');
+    assert.equal(settings.authService, 'authentication');
+    assert.equal(settings.linkStrategy, 'jwt');
+  });
+});
diff --git a/packages/authentication-oauth/tsconfig.json b/packages/authentication-oauth/tsconfig.json
new file mode 100644
index 0000000000..316fd41336
--- /dev/null
+++ b/packages/authentication-oauth/tsconfig.json
@@ -0,0 +1,9 @@
+{
+  "extends": "../../tsconfig",
+  "include": [
+    "src/**/*.ts"
+  ],
+  "compilerOptions": {
+    "outDir": "lib"    
+  }
+}
diff --git a/packages/authentication/src/core.ts b/packages/authentication/src/core.ts
index 04189a5c7c..8ee6efc617 100644
--- a/packages/authentication/src/core.ts
+++ b/packages/authentication/src/core.ts
@@ -2,7 +2,7 @@ import { promisify } from 'util';
 import { merge } from 'lodash';
 import jsonwebtoken, { SignOptions, Secret, VerifyOptions } from 'jsonwebtoken';
 import uuidv4 from 'uuid/v4';
-import { NotAuthenticated, BadRequest } from '@feathersjs/errors';
+import { NotAuthenticated } from '@feathersjs/errors';
 import Debug from 'debug';
 import { Application, Params } from '@feathersjs/feathers';
 import { IncomingMessage, ServerResponse } from 'http';
@@ -244,10 +244,6 @@ export class AuthenticationBase {
     const strategies = this.getStrategies(...names)
       .filter(current => current && typeof current.parse === 'function');
 
-    if (strategies.length === 0) {
-      throw new BadRequest('Authentication HTTP parser needs at least one allowed strategy');
-    }
-
     debug('Strategies parsing HTTP header for authentication information', names);
 
     for (const authStrategy of strategies) {
diff --git a/packages/authentication/src/options.ts b/packages/authentication/src/options.ts
index 6abf50e8a3..492565916d 100644
--- a/packages/authentication/src/options.ts
+++ b/packages/authentication/src/options.ts
@@ -1,5 +1,5 @@
 export default {
-  httpStrategies: [ 'jwt' ],
+  httpStrategies: [],
   jwtStrategies: [],
   jwtOptions: {
     header: { typ: 'access' }, // by default is an access token but can be any type
diff --git a/packages/authentication/src/service.ts b/packages/authentication/src/service.ts
index d36c27289b..4fc779c5bb 100644
--- a/packages/authentication/src/service.ts
+++ b/packages/authentication/src/service.ts
@@ -14,11 +14,11 @@ export class AuthenticationService extends AuthenticationBase implements Service
    * @param _authResult The current authentication result
    * @param params The service call parameters
    */
-  getPayload (_authResult: AuthenticationResult, params: Params) {
+  async getPayload (_authResult: AuthenticationResult, params: Params) {
     // Uses `params.payload` or returns an empty payload
     const { payload = {} } = params;
 
-    return Promise.resolve(payload);
+    return payload;
   }
 
   /**
@@ -29,7 +29,7 @@ export class AuthenticationService extends AuthenticationBase implements Service
    */
   async getJwtOptions (authResult: AuthenticationResult, params: Params) {
     const { service, entity, entityId } = this.configuration;
-    const jwtOptions = merge({}, params.jwt);
+    const jwtOptions = merge({}, params.jwtOptions, params.jwt);
     const hasEntity = service && entity && authResult[entity];
 
     // Set the subject to the entity id if it is available
@@ -53,8 +53,8 @@ export class AuthenticationService extends AuthenticationBase implements Service
    * @param data The authentication request (should include `strategy` key)
    * @param params Service call parameters
    */
-  async create (data: AuthenticationRequest, params?: Params) {
-    const { jwtStrategies } = this.configuration;
+  async create (data: AuthenticationRequest, params: Params) {
+    const jwtStrategies = params.jwtStrategies || this.configuration.jwtStrategies;
 
     if (!jwtStrategies.length) {
       throw new NotAuthenticated('No authentication strategies allowed for creating a JWT (`jwtStrategies`)');
@@ -86,7 +86,7 @@ export class AuthenticationService extends AuthenticationBase implements Service
    * @param id The JWT to remove or null
    * @param params Service call parameters
    */
-  async remove (id: null|string, params?: Params) {
+  async remove (id: null|string, params: Params) {
     const { authentication } = params;
     const { jwtStrategies } = this.configuration;
 
@@ -114,7 +114,7 @@ export class AuthenticationService extends AuthenticationBase implements Service
 
     if (entity !== null) {
       if (service === undefined) {
-        throw new Error(`The 'service' options is not set in the authentication configuration`);
+        throw new Error(`The 'service' option is not set in the authentication configuration`);
       }
 
       if (this.app.service(service) === undefined) {
diff --git a/packages/authentication/test/core.test.ts b/packages/authentication/test/core.test.ts
index e083afe177..f73aacc1d0 100644
--- a/packages/authentication/test/core.test.ts
+++ b/packages/authentication/test/core.test.ts
@@ -104,6 +104,17 @@ describe('authentication/core', () => {
 
       assert.deepStrictEqual(first.configuration, { hello: 'test' });
     });
+
+    it('strategy configuration getter', () => {
+      const [ first ] = auth.getStrategies('first') as [ Strategy1 ];
+      const oldService = auth.configuration.service;
+
+      delete auth.configuration.service;
+
+      assert.strictEqual(first.entityService, null);
+
+      auth.configuration.service = oldService;
+    });
   });
 
   describe('authenticate', () => {
@@ -227,15 +238,10 @@ describe('authentication/core', () => {
   describe('parse', () => {
     const res = {} as ServerResponse;
 
-    it('errors when no names are given', async () => {
+    it('returns null when no names are given', async () => {
       const req = {} as MockRequest;
 
-      try {
-        await auth.parse(req, res);
-        assert.fail('Should never get here');
-      } catch (error) {
-        assert.strictEqual(error.message, 'Authentication HTTP parser needs at least one allowed strategy');
-      }
+      assert.strictEqual(await auth.parse(req, res), null);
     });
 
     it('successfully parses a request (first)', async () => {
diff --git a/packages/authentication/test/service.test.ts b/packages/authentication/test/service.test.ts
index 71af23b32e..682022a834 100644
--- a/packages/authentication/test/service.test.ts
+++ b/packages/authentication/test/service.test.ts
@@ -228,6 +228,22 @@ describe('authentication/service', () => {
       }
     });
 
+    it('throws an error if service name is not set', () => {
+      const otherApp = feathers();
+
+      otherApp.use('/authentication', new AuthenticationService(otherApp, 'authentication', {
+        secret: 'supersecret',
+        jwtStrategies: [ 'first' ]
+      }));
+
+      try {
+        otherApp.setup();
+        assert.fail('Should never get here');
+      } catch (error) {
+        assert.strictEqual(error.message, `The 'service' option is not set in the authentication configuration`);
+      }
+    });
+
     it('throws an error if entity service does not exist', () => {
       const otherApp = feathers();
 
diff --git a/packages/express/index.d.ts b/packages/express/index.d.ts
index 906bb452c4..5bc8b9f680 100644
--- a/packages/express/index.d.ts
+++ b/packages/express/index.d.ts
@@ -14,7 +14,7 @@ export type Application<T = any> = express.Application & FeathersApplication<T>;
 
 export function errorHandler (options?: {
     public?: string,
-    logger?: { error?: (msg: string) => void },
+    logger?: { error?: (msg: string) => void }|null,
     html?: any,
     json?: any
 }): express.ErrorRequestHandler;
@@ -55,4 +55,4 @@ export {
 
 export function parseAuthentication (...strategies: string[]): express.RequestHandler;
 export function authenticate (...strategies: string[]): express.RequestHandler;
-export const original: typeof express;
+export const original: () => express.Application;
diff --git a/packages/express/lib/authentication.js b/packages/express/lib/authentication.js
index 93cdfe6b2b..ec99d7b667 100644
--- a/packages/express/lib/authentication.js
+++ b/packages/express/lib/authentication.js
@@ -1,4 +1,5 @@
 const { flatten, merge } = require('lodash');
+const debug = require('debug')('@feathersjs/express/authentication');
 
 const normalizeStrategy = (_settings = [], ..._strategies) =>
   typeof _settings === 'string'
@@ -25,8 +26,14 @@ exports.parseAuthentication = (settings = {}) => {
 
     const { httpStrategies = [] } = service.configuration;
 
+    if (httpStrategies.length === 0) {
+      debug('No `httpStrategies` found in authentication configuration');
+      return next();
+    }
+
     service.parse(req, res, ...httpStrategies)
       .then(authentication => {
+        debug('Parsed authentication from HTTP header', authentication);
         merge(req, {
           authentication,
           feathers: { authentication }
@@ -48,8 +55,11 @@ exports.authenticate = (...strategies) => {
     const { app, authentication } = req;
     const service = getService(settings, app);
 
+    debug('Authenticating with Express middleware and strategies', settings.strategies);
+
     service.authenticate(authentication, req.feathers, ...settings.strategies)
       .then(authResult => {
+        debug('Merging request with', authResult);
         merge(req, authResult);
 
         next();
diff --git a/tslint.json b/tslint.json
index bda814338b..ed8892ff1b 100644
--- a/tslint.json
+++ b/tslint.json
@@ -8,6 +8,7 @@
       "packages/authentication/lib/**",
       "packages/authentication-local/lib/**",
       "packages/authentication-client/lib/**",
+      "packages/authentication-oauth/lib/**",
       "packages/configuration/lib/**",
       "packages/commons/lib/**",
       "packages/transport-commons/lib/**",