mwoauth2 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mwoauth2-0.1.0/.gitignore +5 -0
- mwoauth2-0.1.0/.gitlab-ci.yml +54 -0
- mwoauth2-0.1.0/.readthedocs.yaml +18 -0
- mwoauth2-0.1.0/CHANGES.md +7 -0
- mwoauth2-0.1.0/CODE_OF_CONDUCT.md +1 -0
- mwoauth2-0.1.0/LICENSE +28 -0
- mwoauth2-0.1.0/Makefile +18 -0
- mwoauth2-0.1.0/PKG-INFO +51 -0
- mwoauth2-0.1.0/README.md +26 -0
- mwoauth2-0.1.0/docs/Makefile +20 -0
- mwoauth2-0.1.0/docs/api.rst +17 -0
- mwoauth2-0.1.0/docs/conf.py +46 -0
- mwoauth2-0.1.0/docs/flask.rst +122 -0
- mwoauth2-0.1.0/docs/index.rst +21 -0
- mwoauth2-0.1.0/docs/other.rst +130 -0
- mwoauth2-0.1.0/docs/requirements.txt +4 -0
- mwoauth2-0.1.0/pyproject.toml +138 -0
- mwoauth2-0.1.0/src/mwoauth2/__init__.py +747 -0
- mwoauth2-0.1.0/src/mwoauth2/py.typed +0 -0
- mwoauth2-0.1.0/stubs/mwapi.py +22 -0
- mwoauth2-0.1.0/tests/__init__.py +0 -0
- mwoauth2-0.1.0/tests/test_mwoauth2.py +592 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
variables:
|
|
2
|
+
PYTHONDONTWRITEBYTECODE: "1"
|
|
3
|
+
# .cache/ is in .gitignore to make sure it’s not included in builds
|
|
4
|
+
HATCH_CACHE_DIR: "$CI_PROJECT_DIR/.cache/hatch"
|
|
5
|
+
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
|
|
6
|
+
|
|
7
|
+
stages:
|
|
8
|
+
- test
|
|
9
|
+
- publish
|
|
10
|
+
|
|
11
|
+
test-job:
|
|
12
|
+
stage: test
|
|
13
|
+
image: docker-registry.svc.toolforge.org/toolforge-python313-sssd-base:latest
|
|
14
|
+
cache:
|
|
15
|
+
- key: pip-python-3.13
|
|
16
|
+
paths:
|
|
17
|
+
- .cache/hatch
|
|
18
|
+
- .cache/pip
|
|
19
|
+
script:
|
|
20
|
+
- python3 -m venv /tmp/venv &&
|
|
21
|
+
. /tmp/venv/bin/activate &&
|
|
22
|
+
python3 -m pip install --upgrade pip &&
|
|
23
|
+
python3 -m pip install hatch &&
|
|
24
|
+
make check
|
|
25
|
+
|
|
26
|
+
publish-job:
|
|
27
|
+
stage: publish
|
|
28
|
+
image: docker-registry.svc.toolforge.org/toolforge-python313-sssd-base:latest
|
|
29
|
+
rules:
|
|
30
|
+
- if: $CI_COMMIT_TAG
|
|
31
|
+
needs:
|
|
32
|
+
- "test-job"
|
|
33
|
+
cache:
|
|
34
|
+
- key: pip-python-3.13
|
|
35
|
+
paths:
|
|
36
|
+
- .cache/hatch
|
|
37
|
+
- .cache/pip
|
|
38
|
+
script:
|
|
39
|
+
- python3 -m venv /tmp/venv &&
|
|
40
|
+
. /tmp/venv/bin/activate &&
|
|
41
|
+
python3 -m pip install --upgrade pip &&
|
|
42
|
+
python3 -m pip install hatch &&
|
|
43
|
+
hatch build &&
|
|
44
|
+
hatch publish
|
|
45
|
+
# add these environment variables in Settings > CI/CD > Variables:
|
|
46
|
+
# - HATCH_INDEX_USER (probably “__token__”)
|
|
47
|
+
# - HATCH_INDEX_AUTH (probably looks like “pypi-[long base64]”)
|
|
48
|
+
# they should be “Masked” (not “Visible”), and “Protect variable” should be checked
|
|
49
|
+
# (the project has a `*` wildcard to protect all tags)
|
|
50
|
+
artifacts:
|
|
51
|
+
untracked: true
|
|
52
|
+
paths:
|
|
53
|
+
- dist/*
|
|
54
|
+
expire_in: 1 week
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
version: "2"
|
|
2
|
+
|
|
3
|
+
build:
|
|
4
|
+
os: "ubuntu-lts-latest"
|
|
5
|
+
tools:
|
|
6
|
+
python: "latest"
|
|
7
|
+
|
|
8
|
+
python:
|
|
9
|
+
install:
|
|
10
|
+
- method: "pip"
|
|
11
|
+
path: "."
|
|
12
|
+
extra_requirements:
|
|
13
|
+
- flask
|
|
14
|
+
- mwapi
|
|
15
|
+
- requirements: docs/requirements.txt
|
|
16
|
+
|
|
17
|
+
sphinx:
|
|
18
|
+
configuration: "docs/conf.py"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
The development of this software is covered by a [Code of Conduct](https://www.mediawiki.org/wiki/Special:MyLanguage/Code_of_Conduct).
|
mwoauth2-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Copyright 2026 Lucas Werkmeister
|
|
2
|
+
|
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
|
4
|
+
modification, are permitted provided that the following conditions are
|
|
5
|
+
met:
|
|
6
|
+
|
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
|
9
|
+
|
|
10
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer in the
|
|
12
|
+
documentation and/or other materials provided with the distribution.
|
|
13
|
+
|
|
14
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
15
|
+
contributors may be used to endorse or promote products derived from
|
|
16
|
+
this software without specific prior written permission.
|
|
17
|
+
|
|
18
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
|
19
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
20
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
21
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
22
|
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
23
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
24
|
+
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
25
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
26
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
27
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
28
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
mwoauth2-0.1.0/Makefile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.PHONY: check fix docs clean
|
|
2
|
+
|
|
3
|
+
HATCH = hatch
|
|
4
|
+
|
|
5
|
+
check:
|
|
6
|
+
$(HATCH) $(HATCHFLAGS) fmt --check
|
|
7
|
+
$(HATCH) $(HATCHFLAGS) run types:check
|
|
8
|
+
$(HATCH) $(HATCHFLAGS) test
|
|
9
|
+
|
|
10
|
+
fix:
|
|
11
|
+
$(HATCH) $(HATCHFLAGS) fmt
|
|
12
|
+
|
|
13
|
+
docs:
|
|
14
|
+
$(HATCH) $(HATCHFLAGS) run docs:build
|
|
15
|
+
|
|
16
|
+
clean:
|
|
17
|
+
$(HATCH) $(HATCHFLAGS) env prune
|
|
18
|
+
$(RM) -r docs/_build/
|
mwoauth2-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mwoauth2
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A library to help with authentication against a MediaWiki site using OAuth 2.
|
|
5
|
+
Project-URL: Issues, https://phabricator.wikimedia.org/tag/mwoauth2/
|
|
6
|
+
Project-URL: Source, https://gitlab.wikimedia.org/toolforge-repos/python-mwoauth2/
|
|
7
|
+
Author-email: Lucas Werkmeister <mail@lucaswerkmeister.de>
|
|
8
|
+
License-Expression: BSD-3-Clause
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: mediawiki,oauth2,wikimedia
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: BSD License
|
|
14
|
+
Classifier: Programming Language :: Python
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.13
|
|
19
|
+
Requires-Dist: requests-oauthlib
|
|
20
|
+
Provides-Extra: flask
|
|
21
|
+
Requires-Dist: flask; extra == 'flask'
|
|
22
|
+
Provides-Extra: mwapi
|
|
23
|
+
Requires-Dist: mwapi; extra == 'mwapi'
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# mwoauth2
|
|
27
|
+
|
|
28
|
+
<!-- This text partially mirrors docs/index.rst; keep them in sync. -->
|
|
29
|
+
|
|
30
|
+
**mwoauth2** is a library to help with authentication against a MediaWiki site using OAuth 2.
|
|
31
|
+
|
|
32
|
+
It is mainly targeted at [Flask](https://flask.palletsprojects.com/) tools
|
|
33
|
+
using the [mwapi](https://pythonhosted.org/mwapi/) library,
|
|
34
|
+
but can be used in other contexts as well.
|
|
35
|
+
Support for other web frameworks or MediaWiki libraries may be added if there is interest.
|
|
36
|
+
|
|
37
|
+
## Documentation and usage
|
|
38
|
+
|
|
39
|
+
See the [documentation](https://mwoauth2.readthedocs.io/),
|
|
40
|
+
which includes instructions for [Flask tools](https://mwoauth2.readthedocs.io/en/latest/flask.html)
|
|
41
|
+
and [non-Flask tools](https://mwoauth2.readthedocs.io/en/latest/other.html).
|
|
42
|
+
|
|
43
|
+
Please note that the library is still relatively new
|
|
44
|
+
and has not been used by many tools yet.
|
|
45
|
+
If anything is unclear or there are problems,
|
|
46
|
+
feel free to reach out to the maintainer(s)
|
|
47
|
+
and/or [file a task on Phabricator](https://phabricator.wikimedia.org/maniphest/task/edit/form/1/?projects=mwoauth2).
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
BSD-3-Clause.
|
mwoauth2-0.1.0/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# mwoauth2
|
|
2
|
+
|
|
3
|
+
<!-- This text partially mirrors docs/index.rst; keep them in sync. -->
|
|
4
|
+
|
|
5
|
+
**mwoauth2** is a library to help with authentication against a MediaWiki site using OAuth 2.
|
|
6
|
+
|
|
7
|
+
It is mainly targeted at [Flask](https://flask.palletsprojects.com/) tools
|
|
8
|
+
using the [mwapi](https://pythonhosted.org/mwapi/) library,
|
|
9
|
+
but can be used in other contexts as well.
|
|
10
|
+
Support for other web frameworks or MediaWiki libraries may be added if there is interest.
|
|
11
|
+
|
|
12
|
+
## Documentation and usage
|
|
13
|
+
|
|
14
|
+
See the [documentation](https://mwoauth2.readthedocs.io/),
|
|
15
|
+
which includes instructions for [Flask tools](https://mwoauth2.readthedocs.io/en/latest/flask.html)
|
|
16
|
+
and [non-Flask tools](https://mwoauth2.readthedocs.io/en/latest/other.html).
|
|
17
|
+
|
|
18
|
+
Please note that the library is still relatively new
|
|
19
|
+
and has not been used by many tools yet.
|
|
20
|
+
If anything is unclear or there are problems,
|
|
21
|
+
feel free to reach out to the maintainer(s)
|
|
22
|
+
and/or [file a task on Phabricator](https://phabricator.wikimedia.org/maniphest/task/edit/form/1/?projects=mwoauth2).
|
|
23
|
+
|
|
24
|
+
## License
|
|
25
|
+
|
|
26
|
+
BSD-3-Clause.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Minimal makefile for Sphinx documentation
|
|
2
|
+
#
|
|
3
|
+
|
|
4
|
+
# You can set these variables from the command line, and also
|
|
5
|
+
# from the environment for the first two.
|
|
6
|
+
SPHINXOPTS ?=
|
|
7
|
+
SPHINXBUILD ?= sphinx-build
|
|
8
|
+
SOURCEDIR = .
|
|
9
|
+
BUILDDIR = _build
|
|
10
|
+
|
|
11
|
+
# Put it first so that "make" without argument is like "make help".
|
|
12
|
+
help:
|
|
13
|
+
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
14
|
+
|
|
15
|
+
.PHONY: help Makefile
|
|
16
|
+
|
|
17
|
+
# Catch-all target: route all unknown targets to Sphinx using the new
|
|
18
|
+
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
|
19
|
+
%: Makefile
|
|
20
|
+
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
:gitlab_url: https://gitlab.wikimedia.org/toolforge-repos/python-mwoauth2/-/blob/main/docs/api.rst
|
|
2
|
+
|
|
3
|
+
API Reference
|
|
4
|
+
=============
|
|
5
|
+
|
|
6
|
+
This page contains the documentation of all the members exported by mwoauth2.
|
|
7
|
+
|
|
8
|
+
Tools should use one of four classes depending on the other libraries they use:
|
|
9
|
+
|
|
10
|
+
* Flask tools that use mwapi should use :class:`~mwoauth2.MWOAuth2FlaskMWApi`.
|
|
11
|
+
* Other Flask tools should use :class:`~mwoauth2.MWOAuth2Flask`.
|
|
12
|
+
* Non-Flask tools that use mwapi should use :class:`~mwoauth2.MWOAuth2MWApi`.
|
|
13
|
+
* Other tools should use :class:`~mwoauth2.MWOAuth2`.
|
|
14
|
+
|
|
15
|
+
.. automodule:: mwoauth2
|
|
16
|
+
:members:
|
|
17
|
+
:imported-members:
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Configuration file for the Sphinx documentation builder.
|
|
2
|
+
#
|
|
3
|
+
# For the full list of built-in configuration values, see the documentation:
|
|
4
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
|
5
|
+
import importlib.metadata
|
|
6
|
+
|
|
7
|
+
import sphinx_rtd_theme
|
|
8
|
+
|
|
9
|
+
# -- Project information -----------------------------------------------------
|
|
10
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
|
|
11
|
+
|
|
12
|
+
metadata = importlib.metadata.metadata('mwoauth2')
|
|
13
|
+
project = metadata['name']
|
|
14
|
+
version = metadata['version']
|
|
15
|
+
author = metadata['author-email'].partition('<')[0].strip()
|
|
16
|
+
|
|
17
|
+
project_copyright = f'2026, {author} and contributors'
|
|
18
|
+
|
|
19
|
+
# -- General configuration ---------------------------------------------------
|
|
20
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
|
21
|
+
|
|
22
|
+
extensions = [
|
|
23
|
+
'sphinx.ext.autodoc',
|
|
24
|
+
'sphinx.ext.intersphinx',
|
|
25
|
+
'sphinx.ext.viewcode',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
templates_path = ['_templates']
|
|
29
|
+
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
|
30
|
+
|
|
31
|
+
intersphinx_mapping = {
|
|
32
|
+
'python': ('https://docs.python.org/', None),
|
|
33
|
+
'django': ('https://docs.djangoproject.com/en/6.1/', None),
|
|
34
|
+
'flask': ('https://flask.palletsprojects.com/en/latest/', None),
|
|
35
|
+
'mwapi': ('https://pythonhosted.org/mwapi/', None),
|
|
36
|
+
'requests_oauthlib': ('https://requests-oauthlib.readthedocs.io/en/latest/', None),
|
|
37
|
+
'toolforge': ('https://python-toolforge.readthedocs.io/en/latest/', None),
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# -- Options for HTML output -------------------------------------------------
|
|
42
|
+
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
|
|
43
|
+
|
|
44
|
+
pygments_style = 'sphinx'
|
|
45
|
+
html_theme = 'sphinx_rtd_theme'
|
|
46
|
+
html_static_path = [sphinx_rtd_theme.get_html_theme_path()]
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
:gitlab_url: https://gitlab.wikimedia.org/toolforge-repos/python-mwoauth2/-/blob/main/docs/flask.rst
|
|
2
|
+
|
|
3
|
+
Using mwoauth2 in a Flask tool
|
|
4
|
+
==============================
|
|
5
|
+
|
|
6
|
+
The basic setup of a Flask tool using mwoauth2 goes as follows:
|
|
7
|
+
|
|
8
|
+
Create the Flask app::
|
|
9
|
+
|
|
10
|
+
app = flask.Flask(__name__)
|
|
11
|
+
|
|
12
|
+
Load the configuration from some secure source.
|
|
13
|
+
For instance, a Toolforge tool may use `Toolforge envvars <https://wikitech.wikimedia.org/wiki/Help:Toolforge/Envvars>`__::
|
|
14
|
+
|
|
15
|
+
app.config.from_prefixed_env('TOOL', loads=yaml.safe_load)
|
|
16
|
+
|
|
17
|
+
This would then load OAuth configuration from the following environment variables:
|
|
18
|
+
|
|
19
|
+
.. code-block:: shell-session
|
|
20
|
+
|
|
21
|
+
$ toolforge envvars create TOOL_OAUTH__CLIENT_ID 'abcde'
|
|
22
|
+
|
|
23
|
+
$ toolforge envvars create TOOL_OAUTH__CLIENT_SECRET
|
|
24
|
+
Enter the value of your envvar (Hit Ctrl+C to cancel): 12345
|
|
25
|
+
|
|
26
|
+
Alternatively (or in addition), you may use a configuration file,
|
|
27
|
+
optionally using the :func:`toolforge.load_private_yaml` helper::
|
|
28
|
+
|
|
29
|
+
app.config.from_file('config.yaml', load=toolforge.load_private_yaml, silent=True)
|
|
30
|
+
|
|
31
|
+
Whichever configuration sources you use,
|
|
32
|
+
``app.config['OAUTH']['CLIENT_ID']`` and ``app.config['OAUTH']['CLIENT_SECRET']`` should be set
|
|
33
|
+
to the client ID and client secret of an OAuth 2 client you registered.
|
|
34
|
+
|
|
35
|
+
Set up a user agent string to use
|
|
36
|
+
(in accordance with the `policy <https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Wikimedia_Foundation_User-Agent_Policy>`__),
|
|
37
|
+
perhaps using :func:`toolforge.set_user_agent` in the case of a Toolforge tool::
|
|
38
|
+
|
|
39
|
+
user_agent = toolforge.set_user_agent('example-tool', email='tool@example.com')
|
|
40
|
+
# or
|
|
41
|
+
user_agent = 'example-tool (tool@example.com) other-details...'
|
|
42
|
+
|
|
43
|
+
Create the OAuth management instance.
|
|
44
|
+
If you’re going to use mwapi, use :class:`~mwoauth2.MWOAuth2FlaskMWApi`::
|
|
45
|
+
|
|
46
|
+
oauth = MWOAuth2FlaskMWApi(
|
|
47
|
+
host='https://meta.wikimedia.org', # the wiki where OAuth authorization will happen
|
|
48
|
+
user_agent=user_agent,
|
|
49
|
+
app=app,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
Otherwise, use :class:`~mwoauth2.MWOAuth2Flask`::
|
|
53
|
+
|
|
54
|
+
oauth = MWOAuth2Flask(
|
|
55
|
+
host='https://meta.wikimedia.org',
|
|
56
|
+
user_agent=user_agent,
|
|
57
|
+
app=app,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
When targeting non-Wikimedia wikis, you may have to specify a custom ``api_path=`` parameter if it is not ``/w/api.php``.
|
|
61
|
+
Also, if you are migrating a tool from OAuth 1.0a to OAuth 2, the ``check_access_token_before_request=True`` parameter may be useful
|
|
62
|
+
(see the API documentation for details).
|
|
63
|
+
|
|
64
|
+
Now the ``oauth`` instance is ready to use.
|
|
65
|
+
To check if the user is logged in, use :meth:`~mwoauth2.MWOAuth2.has_access_token`::
|
|
66
|
+
|
|
67
|
+
@app.route(...)
|
|
68
|
+
def something():
|
|
69
|
+
if oauth.has_access_token():
|
|
70
|
+
# user is logged in
|
|
71
|
+
...
|
|
72
|
+
else:
|
|
73
|
+
# logged out, show a login link
|
|
74
|
+
...
|
|
75
|
+
|
|
76
|
+
To log in, redirect the user to the :meth:`~mwoauth2.MWOAuth2.authorization_url`::
|
|
77
|
+
|
|
78
|
+
@app.route('/login')
|
|
79
|
+
def login():
|
|
80
|
+
return flask.redirect(oauth.authorization_url())
|
|
81
|
+
|
|
82
|
+
In the OAuth callback (the URL of which you configured in our OAuth client registration),
|
|
83
|
+
call :meth:`~mwoauth2.MWOAuth2Flask.fetch_token` to finish logging in::
|
|
84
|
+
|
|
85
|
+
@app.route('/oauth/callback')
|
|
86
|
+
def oauth_callback():
|
|
87
|
+
oauth.fetch_token()
|
|
88
|
+
flask.session.permanent = True
|
|
89
|
+
return flask.redirect(flask.url_for('index'))
|
|
90
|
+
|
|
91
|
+
Now the user is logged in and OAuth is ready to use.
|
|
92
|
+
If you use mwapi, use :meth:`~mwoauth2.MWOAuth2MWApi.mwapi_session`::
|
|
93
|
+
|
|
94
|
+
@app.route('/userinfo')
|
|
95
|
+
def userinfo():
|
|
96
|
+
session = oauth.mwapi_session()
|
|
97
|
+
if session is None:
|
|
98
|
+
return 'not logged in'
|
|
99
|
+
response = session.get(action='query', meta='userinfo')
|
|
100
|
+
return flask.jsonify(response['query']['userinfo'])
|
|
101
|
+
|
|
102
|
+
Otherwise, use :meth:`~mwoauth2.MWOAuth2.oauth2_session`::
|
|
103
|
+
|
|
104
|
+
@app.route('/userinfo')
|
|
105
|
+
def userinfo():
|
|
106
|
+
session = oauth.oauth2_session()
|
|
107
|
+
if session is None:
|
|
108
|
+
return 'not logged in'
|
|
109
|
+
response = session.get('https://meta.wikimedia.org/w/api.php',
|
|
110
|
+
params={'action': 'query', 'meta': 'userinfo', 'format': 'json'})
|
|
111
|
+
return flask.jsonify(response.json()['query']['userinfo'])
|
|
112
|
+
|
|
113
|
+
To log the user out, call :meth:`~mwoauth2.MWOAuth2.pop_access_token`::
|
|
114
|
+
|
|
115
|
+
@app.route('/logout')
|
|
116
|
+
def logout():
|
|
117
|
+
try:
|
|
118
|
+
oauth.pop_access_token()
|
|
119
|
+
except KeyError:
|
|
120
|
+
pass
|
|
121
|
+
flask.session.permanent = False
|
|
122
|
+
return flask.redirect(flask.url_for('index'))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
:gitlab_url: https://gitlab.wikimedia.org/toolforge-repos/python-mwoauth2/-/blob/main/docs/index.rst
|
|
2
|
+
|
|
3
|
+
mwoauth2 documentation
|
|
4
|
+
============================
|
|
5
|
+
|
|
6
|
+
.. This text partially mirrors README.md; keep them in sync.
|
|
7
|
+
|
|
8
|
+
**mwoauth2** is a library to help with authentication against a MediaWiki site using OAuth 2.
|
|
9
|
+
|
|
10
|
+
It is mainly targeted at `Flask <https://flask.palletsprojects.com/>`__ tools
|
|
11
|
+
using the `mwapi <https://pythonhosted.org/mwapi/>`__ library,
|
|
12
|
+
but can be used in other contexts as well.
|
|
13
|
+
Support for other web frameworks or MediaWiki libraries may be added if there is interest.
|
|
14
|
+
|
|
15
|
+
.. toctree::
|
|
16
|
+
:maxdepth: 2
|
|
17
|
+
:caption: Contents:
|
|
18
|
+
|
|
19
|
+
flask
|
|
20
|
+
other
|
|
21
|
+
api
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
:gitlab_url: https://gitlab.wikimedia.org/toolforge-repos/python-mwoauth2/-/blob/main/docs/other.rst
|
|
2
|
+
|
|
3
|
+
Using mwoauth2 in a non-Flask tool
|
|
4
|
+
==================================
|
|
5
|
+
|
|
6
|
+
To use mwoauth2 in a non-Flask tool,
|
|
7
|
+
you will first have to implement an interface to the session store of whichever web framework you’re using,
|
|
8
|
+
by providing six accessor functions:
|
|
9
|
+
``get_oauth_state``, ``set_oauth_state``, and ``pop_oauth_state`` to get, set and pop the OAuth state,
|
|
10
|
+
and ``get_access_token``, ``set_access_token``, and ``pop_access_token`` do the same for the access token.
|
|
11
|
+
For instance, if your session store has a :class:`dict`-like interface, these functions could look like this::
|
|
12
|
+
|
|
13
|
+
def get_oauth_state(session):
|
|
14
|
+
return session.get('oauth_state')
|
|
15
|
+
|
|
16
|
+
def set_oauth_state(state, session):
|
|
17
|
+
session['oauth_state'] = state
|
|
18
|
+
|
|
19
|
+
def pop_oauth_state(session):
|
|
20
|
+
return session.pop('oauth_state')
|
|
21
|
+
|
|
22
|
+
def get_access_token(session):
|
|
23
|
+
return session.get('access_token')
|
|
24
|
+
|
|
25
|
+
def set_access_token(token, session):
|
|
26
|
+
session['access_token'] = token
|
|
27
|
+
|
|
28
|
+
def pop_access_token(session):
|
|
29
|
+
return session.pop('access_token')
|
|
30
|
+
|
|
31
|
+
And you would call mwoauth2 methods with a ``session`` argument, which would be passed through to the accessor functions, for instance::
|
|
32
|
+
|
|
33
|
+
url = oauth.authorization_url(session)
|
|
34
|
+
|
|
35
|
+
If you need more parameters (or fewer) to access the session store, that works too:
|
|
36
|
+
any number of args (and kwargs) are passed through from the mwoauth2 methods to the accessor functions.
|
|
37
|
+
Just make sure that all six functions are consistent in the parameters they take
|
|
38
|
+
(plus the extra ``state``/``token`` parameter of the ``set_*`` functions) –
|
|
39
|
+
if you use a type checker, this will be checked for you automatically.
|
|
40
|
+
|
|
41
|
+
Note that the session store needs to be accessible whenever mwoauth2 is used, not just while the user logs in:
|
|
42
|
+
OAuth 2 access tokens must be refreshed regularly (every 4 hours in Wikimedia production),
|
|
43
|
+
and in order to handle this automatically, mwoauth2 needs to be able to call ``set_access_token`` whenever you make an OAuth-authenticated request.
|
|
44
|
+
|
|
45
|
+
Once the session store accessors are implemented, you can create your mwoauth2 instance,
|
|
46
|
+
generally at tool initialization time (the same instance will be reused between requests)::
|
|
47
|
+
|
|
48
|
+
oauth = MWOAuth2(
|
|
49
|
+
host='https://meta.wikimedia.org', # the wiki where OAuth authorization will happen
|
|
50
|
+
client_id=..., # 32 hexadecimal characters, from some secret config source
|
|
51
|
+
client_secret=..., # 40 hexadecimal characters, ditto
|
|
52
|
+
get_oauth_state=get_oauth_state, # or whatever you called the function
|
|
53
|
+
set_oauth_state=set_oauth_state,
|
|
54
|
+
pop_oauth_state=pop_oauth_state,
|
|
55
|
+
get_access_token=get_access_token,
|
|
56
|
+
set_access_token=set_access_token,
|
|
57
|
+
pop_access_token=pop_access_token,
|
|
58
|
+
user_agent=...,
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
If you use the mwapi library, use the :class:`~mwoauth2.MWOAuth2MWApi` class instead of :class:`~mwoauth2.MWOAuth2`; the constructor parameters are the same.
|
|
62
|
+
The client ID and secret were generated for you when you registered the OAuth 2 client;
|
|
63
|
+
you should store them in some sort of confidential configuration (e.g. environment variables) and load them from there when initializing the tool.
|
|
64
|
+
The ``user_agent`` string must conform with the `policy <https://foundation.wikimedia.org/wiki/Special:MyLanguage/Policy:Wikimedia_Foundation_User-Agent_Policy>`__;
|
|
65
|
+
Toolforge tools can get a suitable string from :func:`toolforge.set_user_agent`::
|
|
66
|
+
|
|
67
|
+
user_agent = toolforge.set_user_agent('example-tool', email='tool@example.com')
|
|
68
|
+
# or
|
|
69
|
+
user_agent = 'example-tool (tool@example.com) other-details...'
|
|
70
|
+
|
|
71
|
+
When targeting non-Wikimedia wikis, you may have to specify a custom ``api_path=`` parameter if it is not ``/w/api.php``.
|
|
72
|
+
|
|
73
|
+
Now the ``oauth`` instance is ready to use.
|
|
74
|
+
To check if the user is logged in, use :meth:`~mwoauth2.MWOAuth2.has_access_token`::
|
|
75
|
+
|
|
76
|
+
def some_route_handler():
|
|
77
|
+
if oauth.has_access_token(session): # or whatever parameters your accessor functions take
|
|
78
|
+
# user is logged in
|
|
79
|
+
...
|
|
80
|
+
else:
|
|
81
|
+
# logged out, show a login link
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
To log in, redirect the user to the :meth:`~mwoauth2.MWOAuth2.authorization_url`::
|
|
85
|
+
|
|
86
|
+
def some_login_handler():
|
|
87
|
+
url = oauth.authorization_url(session) # or whatever parameters your accessor functions take
|
|
88
|
+
return some_redirect_to(url)
|
|
89
|
+
|
|
90
|
+
In the OAuth callback (the URL of which you configured in our OAuth client registration),
|
|
91
|
+
call :meth:`~mwoauth2.MWOAuth2.fetch_token` to finish logging in::
|
|
92
|
+
|
|
93
|
+
def some_oauth_callback():
|
|
94
|
+
request_url = ... # get it from your web framework, somehow
|
|
95
|
+
oauth.fetch_token(request_url, session) # or whatever parameters your accessor functions take
|
|
96
|
+
# ...probably redirect back to the index page
|
|
97
|
+
|
|
98
|
+
Now the user is logged in and OAuth is ready to use.
|
|
99
|
+
If you use mwapi, use :meth:`~mwoauth2.MWOAuth2MWApi.mwapi_session`::
|
|
100
|
+
|
|
101
|
+
def get_userinfo_json():
|
|
102
|
+
session = oauth.mwapi_session(session) # or whatever parameters your accessor functions take
|
|
103
|
+
if session is None:
|
|
104
|
+
return 'not logged in'
|
|
105
|
+
response = session.get(action='query', meta='userinfo')
|
|
106
|
+
return response['query']['userinfo']
|
|
107
|
+
|
|
108
|
+
Otherwise, use :meth:`~mwoauth2.MWOAuth2.oauth2_session`::
|
|
109
|
+
|
|
110
|
+
def get_userinfo_json():
|
|
111
|
+
session = oauth.oauth2_session(session) # or whatever parameters your accessor functions take
|
|
112
|
+
if session is None:
|
|
113
|
+
return 'not logged in'
|
|
114
|
+
response = session.get('https://meta.wikimedia.org/w/api.php',
|
|
115
|
+
params={'action': 'query', 'meta': 'userinfo', 'format': 'json'})
|
|
116
|
+
return response.json()['query']['userinfo']
|
|
117
|
+
|
|
118
|
+
To log the user out, call :meth:`~mwoauth2.MWOAuth2.pop_access_token`::
|
|
119
|
+
|
|
120
|
+
def some_logout_handler():
|
|
121
|
+
try:
|
|
122
|
+
oauth.pop_access_token(session) # or whatever parameters your accessor functions take
|
|
123
|
+
except KeyError:
|
|
124
|
+
pass
|
|
125
|
+
# ...probably redirect back to the index page
|
|
126
|
+
|
|
127
|
+
If you’ve successfully used mwoauth2 with a non-Flask framework,
|
|
128
|
+
feel free to `open a Phabricator task <https://phabricator.wikimedia.org/maniphest/task/edit/form/1/?projects=mwoauth2>`__
|
|
129
|
+
or `create a merge request <https://gitlab.wikimedia.org/toolforge-repos/python-mwoauth2/-/merge_requests>`__
|
|
130
|
+
to add those session store accessor functions to the library itself.
|