TOC¶
Welcome to MedMij OAuth’s documentation¶
The medmij_oauth package assists in implementing an oauth server/client application conform the medmij oauth flow (described here). The module consists of 3 main submodules i.e. medmij_oauth.server, medmij_oauth.client and medmij_oauth.exceptions. The client and server submodules are build for use with an async library like aiohttp.
Beside the package there are two example implementations available on the github repo, an oauth server and client implementation built using these modules (Only a reference, not for production use!).
Server¶
API Reference: medmij_oauth.server
The medmij_oauth.server modules goal is to assist in implementing an oauth server, its main component is the Server class. To make use of the Server class you need to implement the following:
subclass of DataStore (class)
OAuthSession (class)
zg_resource_available (coroutine)
get_ocl (coroutine)
DataStore ABC (server)¶
Your implementation of the DataStore class handles instantiation, persisting and lookups of OAuthSessions.
The methods that you need to implement can be found on the DataStore ABC
.
Example implementation:
from medmij_oauth.server import (
DataStore
)
import my_oauth_session as OAuthSession
SESSIONS = {}
class InMemoryDataStore(DataStore):
async def create_oauth_session(self, response_type, client_id, redirect_uri, scope, state, **kwargs):
oauth_session = OAuthSession(
response_type=response_type,
client_id=client_id,
redirect_uri=redirect_uri,
scope=scope,
state=state
)
SESSIONS[oauth_session.id] = oauth_session
return oauth_session
async def get_oauth_session_by_id(self, oauth_session_id, **kwargs):
return SESSIONS.get(oauth_session_id, None)
async def get_oauth_session_by_authorization_code(self, authorization_code, **kwargs):
try:
oauth_session = [
oauth_session for
oauth_session in SESSIONS.values()
if oauth_session.authorization_code == authorization_code
][0]
except IndexError:
return None
return oauth_session
async def save_oauth_session(self, oauth_session=None, **kwargs):
return oauth_session
def __repr__(self):
return 'InMemoryDataStore()'
Most methods on the Server class use the functions of your implementation of the DataStore to handle interaction with the OAuthSessions. Any extra keyword arguments given to those functions are passed on to the methods on the DataStore implementation e.g. a DB object of some sort
Example:
# In Server Class
async def create_oauth_session(self, request_parameters, **kwargs):
...
oauth_session = await self.data_store.create_oauth_session(
...
**kwargs
)
return oauth_session
OAuthSession (server)¶
This class represents the state of the current oauth session. The Server class will handle instantiation and interaction with OAuthSessions through your implementation of the DataStore ABC.
Example implementation:
class OAuthSession():
def __init__(self, response_type, client_id, redirect_uri, scope, state):
self.id = str(uuid.uuid4())
self.response_type = response_type
self.client_id = client_id
self.scope = scope
self.state = state
self.redirect_uri = redirect_uri
self.created_at = datetime.datetime.now()
self.authorization_code = None
self.authorization_code_expiration = -1
self.authorization_granted = False
self.access_token = None
self.access_token_expiration = -1
self.zorggebruiker_bsn = ''
zg_resource_available¶
An coroutine with signature (client_data:dict, **kwargs:various)->bool
that checks if resources are available for the current zorggebruiker.
Is called when Server.zg_resource_available
is invoked, with a dict containing at least the BSN of the zorggebruiker.
Warning
BSN is added to the OAuthSession in response to the DigiD interaction (FLOW #7), this is not (yet) included in the Server class. If you are implementing a server make sure to update the OAuthSession after retreiving the BSN from DigiD.
get_ocl¶
An coroutine that returns an OCL.
Example implementation:
async def get_ocl():
# Probably some caching and retreiving an up to date list but as an example load it from disk.
async with aiofiles.open('path/to/ocl.xml'), mode='r') as file:
contents = await f.read()
xml = bytes(file.read(), 'utf-8')
return medmij_lists.OAuthclientList(xmldata=xml)
Server usage example¶
from aiohttp import web
import get_db_somehow
import my_get_ocl
import my_datastore_implementation
import my_zg_resouce_available
server = Server(
data_store=my_datastore_implementation,
zg_resource_available=my_zg_resouce_available,
get_ocl=my_get_ocl
)
app['server'] = server
app['db] = get_db_somehow()
async def get_start_oauth_session(request):
query_dict = request.query
server = request.app['server']
oauth_session = await server.create_oauth_session(query_dict, db=request.app['db'])
# If there is no resource available the function raises an OAuthException that gets handled by the middleware
await server.zg_resource_available(oauth_session=oauth_session, client_data={"name": "test patient"})
ocl = await server.get_ocl()
pgo = ocl.get(oauth_session.client_id)
csrf_token = await csrf.generate_csrf_token(request)
return render_template('ask_auth.html', request, {
'pgo': pgo,
'oauth_session_id': oauth_session.id,
'csrf_token': csrf_token
})
app.router.add_get('/oauth/authorize', get_start_session)
app = web.Application()
web.run_app(app, port=args.port)
For a full example implementation checkout the server_implementation on github.
Client¶
API Reference: medmij_oauth.client
The medmij_oauth.client modules goal is to assist in implementing an oauth client, its main component is the Client class. To make use of the Client class you need to implement/supply the following:
subclass of DataStore (class)
OAuthSession (class)
get_zal (coroutine)
get_gnl (coroutine)
client_info (dict)
make_request (coroutine)
DataStore ABC (client)¶
Your implementation of the DataStore class handles instantiation, persisting and lookups of OAuthSessions.
The methods that you need to implement can be found on the DataStore ABC
.
Example implementation:
import secrets
import uuid
from ..data_store import (
DataStore
)
import my_oauth_session as OAuthSession
SESSIONS = {}
class InMemoryDataStore(DataStore):
async def create_oauth_session(self, za_name, gegevensdienst_id, **kwargs):
oauth_session = OAuthSession(
state=secrets.token_hex(16),
za_name=za_name,
gegevensdienst_id=gegevensdienst_id,
scope=gegevensdienst_id
)
SESSIONS[oauth_session.id] = oauth_session
return oauth_session
async def get_oauth_session_by_id(self, oauth_session_id, **kwargs):
return SESSIONS.get(oauth_session_id, None)
async def get_oauth_session_by_state(self, state, **kwargs):
try:
oauth_session = [
oauth_session for
oauth_session in SESSIONS.values()
if oauth_session.state == state
][0]
except IndexError:
return None
return oauth_session
async def save_oauth_session(self, oauth_session=None, **kwargs):
return oauth_session
def __repr__(self):
return 'InMemoryDataStore()'
Most methods on the Client class use the functions of your implementation of the DataStore to handle interaction with the OAuthSessions. Any extra keyword arguments given to those functions are passed on to the methods on the DataStore implementation e.g. a DB object of some sort.
Example:
#In Client class
async def create_oauth_session(self, za_name, gegevensdienst_id, **kwargs):
return await self.data_store.create_oauth_session(
...
**kwargs
)
OAuthSession (client)¶
This class represents the state of the current oauth session. The Server class will handle instantiation and interaction with OAuthSessions through your implementation of the DataStore ABC.
Example implementation:
class OAuthSession():
def __init__(self, state, za_name, gegevensdienst_id, scope):
self.id = str(uuid.uuid4())
self.state = state
self.scope = scope
self.za_name = za_name
self.gegevensdienst_id = gegevensdienst_id
self.authorization_code = None
self.authorized = False
self.access_token = None
get_zal¶
An coroutine that returns a ZAL.
Example implementation:
async def get_zal():
# Probably some caching and retreiving an up to date list but as an example load it from disk.
async with aiofiles.open('path/to/zal.xml'), mode='r') as file:
contents = await f.read()
xml = bytes(file.read(), 'utf-8')
return medmij_lists.ZAL(xmldata=xml)
get_gnl¶
An coroutine that returns a GNL.
Example implementation:
async def get_test_gnl():
# Probably some caching and retreiving an up to date list but as an example load it from disk.
with open(path.join(path.dirname(__file__), 'resources/MedMij_Gegevensdienstnamenlijst_example.xml'), 'r') as file:
xml = bytes(file.read(), 'utf-8')
return medmij_lists.GNL(xmldata=xml)
client_info¶
Dict containing info about the client application e.i. client_id and redirect_url for authorization request responses.
Example:
client_info = {
"client_id": "oauthclient.local",
"redirect_url": "https://oauthclient.local/oauth/cb"
}
make_request¶
Coroutine that makes a POST request. Should have the signature (url:string, body:dict)->dict
.
Used by the client to make a exchange_authorization_code
request to the oauth server.
Example:
# Example uses aiohttp client (https://docs.aiohttp.org/en/stable/client.html) to make the actual request.
# For a complete example of how to implement this check out the example client implementation.
async def make_request(self, url='', body=None):
optional_data = {}
if body is not None:
if not isinstance(body, str):
body = json.dumps(body)
optional_data['data'] = body.encode('utf-8')
async with self.session.request("POST", url, **optional_data) as resp:
json_resp = await resp.json()
return json_resp
Client usage example¶
from aiohttp import web
import get_db_somehow
import my_datastore_implementation
import my_get_zal
import my_get_gnl
import my_make_request
client_info = {
"client_id": "oauthclient.local",
"redirect_url": "https://oauthclient.local/oauth/cb"
}
client = Client(
data_store=my_datastore_implemtation,
get_zal=my_get_zal,
get_gnl=my_get_gnl,
make_request=my_make_request,
client_info=client_info
)
app['client'] = client
app['db] = get_db_somehow()
async def get_start_session(request):
client = request.app['client']
client = request.app['db']
session = await create_oauth_session(request_params, db=db)
app.router.add_get('/oauth/start', get_start_session)
app = web.Application()
web.run_app(app, port=args.port)
For a full example implementation checkout the client_implementation on github.
Exceptions¶
API Reference: medmij_oauth.exceptions
The OAuthException class is used to represent an error as described in rfc6749. The exception contains the error, error_description, if it is allowed to redirect, redirect_url if allowed and correct HTTP status_code.
The different possible errors are contained in the ERRORS
enum. Further optional arguments that the OAuthException’s constructor takes are, error_descripion, redirect and redirect_url.
Example Usage:
raise OAuthException(ERRORS.INVALID_REQUEST, error_description='Invalid redirect url', redirect=False)
raise OAuthException(ERRORS.UNAUTHORIZED_CLIENT, error_description='No such resource', redirect=True, base_redirect_url='https://oauthclient.com')
Example of OAuth exception handling in middleware
...
async def oauth_error_middleware(request, handler):
try:
response = await handler(request)
return response
except OAuthException as ex:
# If redirect is set on the exception, it is safe to redirect zorggebruiker to supplied redirect url
if ex.redirect:
return web.HTTPFound(ex.get_redirect_url())
# Else just render to screen with the correct HTTP statuscode
return web.Response(
text=ex.get_json(),
status=ex.status_code,
content_type='application/json'
)
The MedMij OAuth flow¶
In the API references you find links to this flow, that means that those functions assist in implementing this step of the oauth flow. (e.g. Server.create_oauth_session
)
De PGO Server start de flow door in de PGO Presenter van de Zorggebruiker de mogelijkheid te presenteren om een bepaalde Gegevensdienst bij een zekere Zorgaanbieder te verzamelen. Het gaat altijd om precies één Gegevensdienst (één scope, in OAuth-termen). Uit de Zorgaanbiederslijst weet de PGO Server welke Gegevensdiensten voor een Zorgaanbieder beschikbaar zijn. Desgewenst worden de Gegevensdienstnamen uit de Gegevensdienstnamenlijst gebruikt.
De Zorggebruiker maakt expliciet zijn selectie en laat de OAuth User Agent een verzamel-verzoek sturen naar de Authorization Server. Het adres van het authorization endpoint komt uit de ZAL. De redirect URI geeft aan waarnaartoe de Authorization Server de OAuth User Agent verderop moet redirecten (met de authorization code).
Daarop begint de Authorization Server de OAuth-flow (in zijn rol als OAuth Authorization Server) door een sessie te creëren.
Dan start de Authorization Server (nu in de rol van SAML Service Provider) de SAML-flow door de browser naar DigiD te redirecten, onder meegeven van een redirect URI, die aangeeft waarnaartoe DigiD straks de OAuth User Agent moet terugsturen, na het inloggen van de Zorggebruiker.
DigiD vraagt van de Zorggebruiker via zijn PGO Presenter om inloggegevens.
Wanneer deze juist zijn, redirect DigiD de OAuth User Agent terug naar de Authorization Server, onder meegeven van een ophaalbewijs: het SAML-artefact.
Met dit ophaalbewijs haalt de Authorization Server rechtstreeks bij DigiD het BSN op.
De Authorization Server controleert alvast of de Zorgaanbieder voor de betreffende Gegevensdienst überhaupt gezondheidsinformatie van die Persoon beschikbaar heeft. Daarvan maakt deel uit dat de Persoon daarvoor minstens 16 jaar oud moet zijn.
Zo ja, dan presenteert de Authorization Server via de PGO Presenter aan Zorggebruiker de vraag of laatstgenoemde hem toestaat de gevraagde persoonlijke gezondheidsinformatie aan de PGO Server (als OAuth Client) te sturen. Onder het flow-diagram staat gespecificeerd welke informatie, waarvandaan, de OAuth Authorization Server verwerkt in de aan Zorggebruiker voor te leggen autorisatievraag.
Bij akkoord logt de Authorization Server dit als toestemming, genereert een authorization code en stuurt dit als ophaalbewijs, door middel van een browser redirect met de in stap 1 ontvangen redirect URI, naar de PGO Server. De Authorization Server stuurt daarbij de local state-informatie mee die hij in de eerste stap van de PGO Server heeft gekregen. Laatstgenoemde herkent daaraan het verzoek waarmee hij de authorization code moet associëren.
De PGO Server vat niet alleen deze authorization code op als ophaalbewijs, maar leidt er ook uit af dat de toestemming is gegeven en logt het verkrijgen van het ophaalbewijs.
Met dit ophaalbewijs wendt de PGO Server zich weer tot de Authorization Server, maar nu zonder tussenkomst van de OAuth User Agent, voor een access token.
Daarop genereert de Authorization Server een access token en stuurt deze naar de PGO Server.
Nu is de PGO Server gereed om het verzoek om de gezondheidsinformatie naar de Resource Server te sturen. Het adres van het resource endpoint haalt hij uit de ZAL. Hij plaatst het access token in het bericht en zorgt ervoor dat in het bericht geen BSN is opgenomen.
De Resource Server controleert of het ontvangen token recht geeft op de gevraagde resources, haalt deze (al dan niet) bij achterliggende bronnen op en verstuurt ze in een FHIR-response naar de PGO Server.
Deze bewaart de ontvangen gezondheidsinformatie in het persoonlijke dossier. Mocht de Gegevensdienst waartoe de Zorggebruiker heeft geautoriseerd uit meerdere Transacties bestaan, bevraagt de PGO Server de Resource Server daarna mogelijk opnieuw voor de nog resterende Transacties , eventueel na nieuwe gebruikersinteractie. Zolang het access token geldig is, kan dat.
Tests¶
$ pytest -v
Requirements¶
Modules¶
Python >=3.7
Example implementations¶
aiohttp==3.3.2
aiohttp-jinja2==1.0.0
aiohttp-session==2.5.1
cryptography==2.3
SQLAlchemy==1.2.10
Tests¶
pytest==3.7.1
pytest-asyncio==0.9.0
License¶
This project is licensed under the AGPL-3.0 License - see the LICENSE file for details
medmij_oauth.server module¶
Server¶
- class medmij_oauth.server.Server(data_store=None, zg_resource_available=None, get_ocl=None)[source]¶
Class to assist in the OAuth serverside flow
- Parameters
data_store (
DataStore
) – Must be subclass of DataStore, handles data interaction with OAuthSessions seeDataStore
for more info.zg_resource_available (function) – Function that is called by Server.zg_resource_available to determine if resources are available for zorggebruiker.
get_ocl (function) – Function that returns a OCL
- coroutine create_oauth_session(request_parameters, **kwargs)[source]¶
Create and return a new OAuthSession. (FLOW #3)
- Parameters
request_parameters (dict) – Dictionary containing the request parameters from the start verzamelen.
**kwargs (various) – Keyword arguments get passed on to the data_store.create_oauth_session function, e.g. db object
- Returns
The created OAuthSession
- Return type
- Raises
OAuthException – If supplied request_parameters are not valid
- coroutine exchange_authorization_code(request_parameters, **kwargs)[source]¶
Handle the oauth client’s request to exchange the authorization code for an access token. (FLOW #13)
- Parameters
request_parameters (str) – Params send with the request.
**kwargs (various) – Keyword arguments get passed on to the various DataStore functions, e.g. db object
- Returns
Dict containing the parameters for a valid response, including the access_token, token_type, expires_in and scope
- Return type
dict
- Raises
OAuthException – If request parameters are invalid
- coroutine get_ocl()[source]¶
Return the OCL returned by the get_ocl function supplied in instantiation of Server object
- coroutine handle_auth_grant(oauth_session_id=None, authorized=False, **kwargs)[source]¶
Handle the zorggebruikers response to the authorization question. (FLOW #10)
- Parameters
oauth_session_id (str) – ID for the OAuthSession of current zorggebruiker.
authorized (bool) – Indicates if zorggebruiker response was negative (False) or positive (True)
**kwargs (various) – Keyword arguments get passed on to self.data_store.get_oauth_session_by_id and self.data_store.save_oauth_session
- Returns
Tuple containing the updated OAuthSession (with authorization_code and authorization_code_expiration) and the redirect_url
- Return type
tuple (OAuthSession, str)
- Raises
OAuthException – If zorggebruiker response was negative
- coroutine zg_resource_available(oauth_session=None, oauth_session_id=None, client_data={}, **kwargs)[source]¶
Determine if this service has resources available for this zorggebruikers by calling the supplied zg_resource_available function on instatiation of the Server. (FLOW #8)
This function requires a least an oauth_session or an oauthsession id. BSN is added to the client_data that is passed to the self._zg_resource_available function.
- Parameters
oauth_session (OAuthSession) – OAuthSession for the current zorggebruiker (optional).
oauth_session_id (string) – ID for the OAuthSession of current zorggebruiker (optional).
client_data (dict) – Optional additional zorggebruikerinfo that gets passed on to the self._zg_resource_available function.
**kwargs (various) – Keyword arguments get passed to the supplied self._zg_resource_available function
- Returns
returns True if resouces are available for this zorggebruiker
- Return type
bool
- Raises
OAuthException – If there is no resource available for this zorggebruiker
Datastore¶
- class medmij_oauth.server.DataStore[source]¶
Bases:
abc.ABC
Abstract Class that handles interaction instantiation, persisting and lookups of OAuthSessions.
- coroutine create_oauth_session(response_type, client_id, redirect_uri, scope, state, **kwargs)[source]¶
Create a new oauth_session, persist the oauth_session and return it.
- coroutine get_oauth_session_by_authorization_code(authorization_code, **kwargs)[source]¶
Get a oauth_session based on its authorization_code and return it, else return None
OAuthSession¶
Class that should be implemented by implementor of the OAuth Server. This class is should be instantiated by your implementation of the DataStore base class and represents the current state of your OAuth Session.
The OAuthSession should at least have the following attributes:
id (uuid)
response_type (string)
client_id (string)
scope (string)
state (string)
redirect_uri (string)
authorization_code (string)
authorization_code_expiration (datetime.datetime)
authorization_granted (boolean)
access_token (string)
access_token_expiration (datetime.datetime)
zorggebruiker_bsn (string)
Example implementation:
class OAuthSession():
def __init__(self, response_type, client_id, redirect_uri, scope, state):
self.id = str(uuid.uuid4())
self.response_type = response_type
self.client_id = client_id
self.scope = scope
self.state = state
self.redirect_uri = redirect_uri
self.created_at = datetime.datetime.now()
self.authorization_code = None
self.authorization_code_expiration = -1
self.authorization_granted = False
self.access_token = None
self.access_token_expiration = -1
self.zorggebruiker_bsn = ''
medmij_oauth.client module¶
Client¶
- class medmij_oauth.client.Client(data_store=None, get_zal=None, get_gnl=None, client_info=None, make_request=None)[source]¶
Class to assist in the OAuth clientside flow
- Parameters
data_store (
DataStore
) – Must be subclass of DataStore, handles data interaction with OAuthSessions seeDataStore
for more info.get_zal (coroutine) – Function that returns a ZAL
get_gnl (coroutine) – Function that returns a GegevensdienstNamenlijst
client_info (dict) – Dict containing info about the client application (client_id and redirect_url for authorization request responses)
make_request (coroutine) – coroutine that makes a post request. Should have the signature
(url:string, body:dict)->dict
. Used to make a authorization exchange request to the oauth server.
- coroutine create_auth_request_url(oauth_session)[source]¶
Build and return authorization request url (FLOW #2)
- Parameters
oauth_session (OAuthSession) – OAuthSession for current zorggebruiker
- Returns
The authorization request url
- Return type
str
- coroutine create_oauth_session(za_name, gegevensdienst_id, **kwargs)[source]¶
Create and return a new OAuthSession to start the oauth flow. Add the zorggebruikers choice of zorgaanbieder gegevensdienst. (FLOW #2)
- Parameters
za_name (string) – Name of zorgaanbieder chosen by the zorggebruiker.
gegevensdienst_id (string) – Id of the gegevensdienst chosen by the zorggebruiker
**kwargs (various) – Keyword arguments get passed on to the data_store.create_oauth_session function, e.g. db object
- Returns
The created OAuthSession
- Return type
- coroutine exchange_authorization_code(oauth_session, **kwargs)[source]¶
Make a request to a oauth server with the supplied make_request function on instantiation of the Client, exchange the received authorization code for an access token and update the oauth_session. (FLOW #12)
- Parameters
oauth_session (OAuthSession) – Authorized oauth session of which to exchange the authorization code
**kwargs (various) – Keyword arguments get passed on to the data_store.save_oauth_session function, e.g. db object
- Returns
The updated OAuthSession containing the access_token
- Return type
- Raises
OAuthException – If the server’s response is invalid
- coroutine get_zal()[source]¶
Return a tuple of the ZAL and GNL (zal, gnl) returned by the get_zal and get_gnl function supplied in instantiation of Client object
- coroutine handle_auth_response(parameters, **kwargs)[source]¶
Handles the response to the authorization request. (FLOW #10, FLOW #11)
- Parameters
parameters (dict) – The query params from the servers’s response to the authorization request
**kwargs (various) – Keyword arguments get passed on to the data_store.get_oauth_session_by_state function, e.g. db object
- Returns
The updated OAuthSession no containing the authorization_code, and authorized set to True
- Return type
- Raises
OAuthException – If validation of the params fails
ValueError – If there is no session found linked to the state parameter in the provided query parameters
Datastore¶
- class medmij_oauth.client.DataStore[source]¶
Bases:
abc.ABC
Abstract Class that handles interaction instantiation, persisting and lookups of OAuthSessions.
- coroutine create_oauth_session(state, za_name, gegevensdienst_id, scope, **kwargs)[source]¶
Create a new oauth_session, persist the oauth_session and return it.
- coroutine get_oauth_session_by_id(oauth_session_id, **kwargs)[source]¶
Get a oauth_session based on it’s id and return it, else return None
OAuthSession¶
Class that should be implemented by implementor of the OAuth client. This class is should be instantiated by your implementation of the DataStore base class and represents the current state of an OAuth Session.
The OAuthSession should at least have the following attributes:
id (uuid)
state (string)
scope (string)
za_name (string)
gegevensdienst_id (string)
authorization_code (string)
authorized (boolean)
access_token (string)
Example implementation:
class OAuthSession():
def __init__(self, state, za_name, gegevensdienst_id, scope):
self.id = str(uuid.uuid4())
self.state = state
self.scope = scope
self.za_name = za_name
self.gegevensdienst_id = gegevensdienst_id
self.authorization_code = None
self.authorized = False
self.access_token = None
medmij_oauth.exceptions module¶
Module for handling OAuth related errors as specified in rfc6749
OAuthException¶
- exception medmij_oauth.exceptions.OAuthException(error_code, error_description='', redirect=False, base_redirect_url='')[source]¶
OAuthException class, represents a oauth error as described in rfc6749
- Parameters
error_code (
error code
) – Int that represents a type of errorerror_description (string) – Human readable description of the error e.g. ‘no such resource’
redirect (bool) – Indication if on handling of the exception the user should be redirected back to the client application of if the error should be rendered to the screen
base_redirect_url (string (optional)) – The base of the redirect url (on redirection the error params are appended to the base_redirect_url as a query string)
Usage examples:
raise OAuthException(ERRORS.INVALID_REQUEST, error_description='Invalid redirect url', redirect=False)
raise OAuthException(ERRORS.UNAUTHORIZED_CLIENT, error_description='No such resource', redirect=True, base_redirect_url='https://oauthclient.com')
- get_dict()[source]¶
Return dict representation of the exception that is targeted at the end user. Included properties are ‘error’ and ‘error_description’.
- get_json()[source]¶
Return json representation of the exception that is targeted at the end user Included properties are ‘error’ and ‘error_description’
{ 'error': 'unauthorized_client', 'error_description': 'no such resource' }
- get_redirect_url()[source]¶
Return redirect url to which the end user should be redirected. The redirect_url constists of two parts, self.base_redirect_url and a query string that contains the error and error description
Raises a Exception if self.direct != True or if self.base_redirect_url is not set.
e.g.
https://oauthclient.com/cb/?error=unauthorized_client&error_description=No%20such%20resource
Error codes¶
- medmij_oauth.exceptions.lookup_error_code(error)[source]¶
Lookup error code by text. When an oauth client receives a error response, it can reproduce the exception by looking up the error code with the ‘error’ query param that it received.
Raises a ValueError if the error passed to it is unknown.
Example:
error = query_params.get('error') error_description = query_params.get('error_description') raise OAuthException(error_code=lookup_error_code(error), error_description=error_description)
- class medmij_oauth.exceptions.ERRORS(value)[source]¶
Error codes enum to be used as error_code for instantiation of OAuthException
Usage example:
raise OAuthException(ERRORS.UNAUTHORIZED_CLIENT, 'no such resource', ...)
- ACCESS_DENIED = 2¶
- INVALID_CLIENT = 8¶
- INVALID_GRANT = 9¶
- INVALID_REQUEST = 1¶
- INVALID_SCOPE = 5¶
- SERVER_ERROR = 6¶
- TEMPORARILY_UNAVAILABLE = 7¶
- UNAUTHORIZED_CLIENT = 3¶
- UNSUPPORTED_GRANT_TYPE = 10¶
- UNSUPPORTED_RESPONSE_TYPE = 4¶