diff --git a/tests/test_oauth2.py b/tests/test_oauth2.py
index 17d9cb701f9a0b7afefe24f1cf6e0057df923594..592f8610caccbbe2277bbe1b1026f8129b674693 100644
--- a/tests/test_oauth2.py
+++ b/tests/test_oauth2.py
@@ -172,6 +172,16 @@ class TestViews(UffdTestCase):
 		self.assertEqual(r.json['token_type'], 'Bearer')
 		self.assertEqual(r.json['scope'], 'profile')
 
+	# Regression test for #114 (OAuth2 token endpoint does not support Basic-Auth)
+	def test_token_basicauth(self):
+		r = self.client.post(path=url_for('oauth2.token'),
+			data={'grant_type': 'authorization_code', 'code': self.get_auth_code(), 'redirect_uri': 'http://localhost:5009/callback'},
+			headers={'Authorization': f'Basic dGVzdDp0ZXN0c2VjcmV0'}, follow_redirects=True)
+		self.assertEqual(r.status_code, 200)
+		self.assertEqual(r.content_type, 'application/json')
+		self.assertEqual(r.json['token_type'], 'Bearer')
+		self.assertEqual(r.json['scope'], 'profile')
+
 	def test_token_invalid_code(self):
 		r = self.client.post(path=url_for('oauth2.token'),
 			data={'grant_type': 'authorization_code', 'code': 'abcdef', 'redirect_uri': 'http://localhost:5009/callback', 'client_id': 'test', 'client_secret': 'testsecret'}, follow_redirects=True)
diff --git a/uffd/oauth2/views.py b/uffd/oauth2/views.py
index 3b580aef038a4deff37347ba7584c17475caaf71..57a7e9bfceb1a6f9ff9f46ac54e779f41bb29de3 100644
--- a/uffd/oauth2/views.py
+++ b/uffd/oauth2/views.py
@@ -1,6 +1,7 @@
 import datetime
 import functools
 import secrets
+import urllib.parse
 
 from flask import Blueprint, request, jsonify, render_template, session, redirect, url_for, flash, abort
 import oauthlib.oauth2
@@ -29,6 +30,16 @@ class UffdRequestValidator(oauthlib.oauth2.RequestValidator):
 			return False
 
 	def authenticate_client(self, oauthreq, *args, **kwargs):
+		authorization = oauthreq.extra_credentials.get('authorization')
+		if authorization:
+			# From RFC6749 2.3.1:
+			# Clients in possession of a client password MAY use the HTTP Basic authentication
+			# scheme as defined in [RFC2617] to authenticate with the authorization server.
+			# The client identifier is encoded using the "application/x-www-form-urlencoded"
+			# encoding algorithm per Appendix B, and the encoded value is used as the username
+			# the client password is encoded using the same algorithm and used as the password.
+			oauthreq.client_id = urllib.parse.unquote(authorization.username)
+			oauthreq.client_secret = urllib.parse.unquote(authorization.password)
 		if oauthreq.client_secret is None:
 			return False
 		try:
@@ -203,7 +214,8 @@ def authorize():
 
 @bp.route('/token', methods=['GET', 'POST'])
 def token():
-	headers, body, status = server.create_token_response(request.url, request.method, request.form, request.headers)
+	headers, body, status = server.create_token_response(request.url, request.method, request.form,
+	                                                     request.headers, {'authorization': request.authorization})
 	return body, status, headers
 
 def oauth_required(*scopes):