[#8461] include oauth_callback in our example clients, to match spec
diff --git a/Allura/docs/api-rest/docs.md b/Allura/docs/api-rest/docs.md
index 425ae89..8865147 100755
--- a/Allura/docs/api-rest/docs.md
+++ b/Allura/docs/api-rest/docs.md
@@ -93,7 +93,7 @@
     AUTHORIZE_URL = 'https://forge-allura.apache.org/rest/oauth/authorize'
     ACCESS_TOKEN_URL = 'https://forge-allura.apache.org/rest/oauth/access_token'
     
-    oauth = OAuth1Session(CONSUMER_KEY, client_secret=CONSUMER_SECRET)
+    oauth = OAuth1Session(CONSUMER_KEY, client_secret=CONSUMER_SECRET, callback_uri='oob')
     
     # Step 1: Get a request token. This is a temporary token that is used for 
     # having the user authorize an access token and to sign the request to obtain 
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..840326b
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,223 @@
+#
+# This file is autogenerated by pip-compile with python 3.7
+# To update, run:
+#
+#    pip-compile
+#
+activitystream==0.4.0
+    # via -r requirements.in
+beaker==1.11.0
+    # via -r requirements.in
+beautifulsoup4==4.11.1
+    # via
+    #   -r requirements.in
+    #   webtest
+bleach[css]==5.0.1
+    # via pypeline
+cchardet==2.1.7
+    # via -r requirements.in
+certifi==2021.10.8
+    # via requests
+cffi==1.15.1
+    # via cryptography
+charset-normalizer==2.0.12
+    # via requests
+colander==1.8.3
+    # via -r requirements.in
+crank==0.8.1
+    # via turbogears2
+creoleparser==0.7.5
+    # via pypeline
+cryptography==37.0.4
+    # via -r requirements.in
+datadiff==2.0.0
+    # via -r requirements.in
+decorator==5.1.1
+    # via -r requirements.in
+docutils==0.18.1
+    # via pypeline
+easywidgets==0.4.1
+    # via -r requirements.in
+emoji==1.7.0
+    # via -r requirements.in
+feedgenerator==2.0.0
+    # via -r requirements.in
+feedparser==6.0.10
+    # via -r requirements.in
+formencode==2.0.1
+    # via
+    #   -r requirements.in
+    #   easywidgets
+genshi==0.7.7
+    # via creoleparser
+gitdb==4.0.9
+    # via gitpython
+gitpython==3.1.27
+    # via -r requirements.in
+gunicorn==20.1.0
+    # via -r requirements.in
+html5lib==1.1
+    # via
+    #   -r requirements.in
+    #   pypeline
+    #   textile
+idna==3.3
+    # via requests
+importlib-metadata==4.12.0
+    # via markdown
+inflection==0.5.1
+    # via profanityfilter
+iso8601==1.0.2
+    # via colander
+jinja2==3.1.2
+    # via -r requirements.in
+markdown==3.3.7
+    # via
+    #   -r requirements.in
+    #   markdown-checklist
+    #   pypeline
+markdown-checklist==0.4.3
+    # via -r requirements.in
+markupsafe==2.1.0
+    # via
+    #   -r requirements.in
+    #   easywidgets
+    #   jinja2
+    #   turbogears2
+    #   webhelpers2
+ming==0.12.1
+    # via -r requirements.in
+mock==4.0.3
+    # via -r requirements.in
+oauthlib==3.2.1
+    # via
+    #   -r requirements.in
+    #   requests-oauthlib
+paginate==0.5.6
+    # via -r requirements.in
+paste==3.5.1
+    # via
+    #   -r requirements.in
+    #   easywidgets
+    #   pastescript
+pastedeploy==2.1.1
+    # via
+    #   -r requirements.in
+    #   pastescript
+pastescript==3.2.1
+    # via -r requirements.in
+pillow==9.2.0
+    # via -r requirements.in
+profanityfilter==2.0.6
+    # via -r requirements.in
+pycparser==2.21
+    # via cffi
+pyflakes==2.4.0
+    # via -r requirements.in
+pygments==2.12.0
+    # via -r requirements.in
+pymongo==3.11.4
+    # via
+    #   -r requirements.in
+    #   activitystream
+    #   ming
+pypeline[creole,markdown,rst,textile]==0.6.0
+    # via -r requirements.in
+pysolr==3.9.0
+    # via -r requirements.in
+python-dateutil==2.8.2
+    # via
+    #   -r requirements.in
+    #   easywidgets
+python-magic==0.4.27
+    # via -r requirements.in
+python-oembed==0.2.4
+    # via -r requirements.in
+pytz==2022.1
+    # via
+    #   -r requirements.in
+    #   feedgenerator
+    #   ming
+qrcode==7.3.1
+    # via -r requirements.in
+regex==2022.6.2
+    # via
+    #   regex-as-re-globally
+    #   textile
+regex-as-re-globally==0.0.2
+    # via -r requirements.in
+repoze-lru==0.7
+    # via turbogears2
+requests==2.27.1
+    # via
+    #   -r requirements.in
+    #   pysolr
+    #   requests-oauthlib
+requests-oauthlib==1.3.1
+    # via -r requirements.in
+setproctitle==1.2.3
+    # via -r requirements.in
+sgmllib3k==1.0.0
+    # via feedparser
+six==1.16.0
+    # via
+    #   -r requirements.in
+    #   bleach
+    #   creoleparser
+    #   easywidgets
+    #   formencode
+    #   genshi
+    #   html5lib
+    #   paste
+    #   pastescript
+    #   python-dateutil
+    #   webhelpers2
+smmap==5.0.0
+    # via gitdb
+soupsieve==2.3.2.post1
+    # via beautifulsoup4
+testfixtures==6.18.5
+    # via -r requirements.in
+textile==4.0.2
+    # via pypeline
+timermiddleware==0.6.2
+    # via -r requirements.in
+tinycss2==1.1.1
+    # via bleach
+translationstring==1.4
+    # via colander
+turbogears2==2.3.12
+    # via -r requirements.in
+typing-extensions==4.3.0
+    # via
+    #   gitpython
+    #   importlib-metadata
+urllib3==1.26.9
+    # via requests
+waitress==2.1.2
+    # via webtest
+webencodings==0.5.1
+    # via
+    #   bleach
+    #   html5lib
+    #   tinycss2
+webhelpers2==2.0
+    # via -r requirements.in
+webob==1.7.4
+    # via
+    #   -r requirements.in
+    #   easywidgets
+    #   timermiddleware
+    #   turbogears2
+    #   webtest
+webtest==3.0.0
+    # via -r requirements.in
+werkzeug==2.1.2
+    # via -r requirements.in
+wrapt==1.14.1
+    # via -r requirements.in
+zipp==3.8.0
+    # via importlib-metadata
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
diff --git a/scripts/wiki-copy.py b/scripts/wiki-copy.py
index fc65537..ddb3187 100644
--- a/scripts/wiki-copy.py
+++ b/scripts/wiki-copy.py
@@ -81,7 +81,7 @@
         oauth_token = cp.get(base_url, 'oauth_token')
         oauth_token_secret = cp.get(base_url, 'oauth_token_secret')
     except NoOptionError:
-        oauthSess = OAuth1Session(oauth_key, client_secret=oauth_secret)
+        oauthSess = OAuth1Session(oauth_key, client_secret=oauth_secret, callback_uri='oob')
         request_token = oauthSess.fetch_request_token(REQUEST_TOKEN_URL)
         pin_url = oauthSess.authorization_url(AUTHORIZE_URL, request_token['oauth_token'])
         if isinstance(webbrowser.get(), webbrowser.GenericBrowser):