Skip to content

Commit

Permalink
Add ScriptAuthorizer that supports personal-use script OAuth.
Browse files Browse the repository at this point in the history
  • Loading branch information
bboe committed Feb 14, 2016
1 parent 3b8b042 commit 0ff6209
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 2 deletions.
3 changes: 2 additions & 1 deletion prawcore/__init__.py
@@ -1,7 +1,8 @@
"""prawcore: Low-level communication layer for PRAW 4+."""

import logging
from .auth import Authenticator, Authorizer, ReadOnlyAuthorizer # noqa
from .auth import (Authenticator, Authorizer, ReadOnlyAuthorizer, # noqa
ScriptAuthorizer)
from .const import __version__ # noqa
from .exceptions import * # noqa
from .sessions import Session, session # noqa
Expand Down
33 changes: 32 additions & 1 deletion prawcore/auth.py
@@ -1,7 +1,7 @@
"""Provides Authentication and Authorization classes."""
import time
from . import const, util
from .exceptions import InvalidInvocation, RequestException
from .exceptions import InvalidInvocation, OAuthException, RequestException
from requests.status_codes import codes


Expand Down Expand Up @@ -46,6 +46,10 @@ def _request_token(self, **data):

payload = response.json()

if 'error' in payload: # Why are these OKAY responses?
raise OAuthException(response, payload['error'],
payload.get('error_description'))

self._expiration_timestamp = time.time() + payload['expires_in']
self.access_token = payload['access_token']
self.scopes = set(payload['scope'].split(' '))
Expand Down Expand Up @@ -79,3 +83,30 @@ class ReadOnlyAuthorizer(Authorizer):
def refresh(self):
"""Obtain a new ReadOnly access token."""
self._request_token(grant_type='client_credentials')


class ScriptAuthorizer(Authorizer):
"""Manages personal-use script type authorizations.
Only users who are listed as developers for the application will be
granted access tokens.
"""

def __init__(self, authenticator, username, password):
"""Represent a single personal-use authorization to reddit's API.
:param authenticator: An instance of :class:`Authenticator`.
:param username: The reddit username of one of the application's
developers.
:param password: The password associated with ``username``.
"""
super(ScriptAuthorizer, self).__init__(authenticator)
self._username = username
self._password = password

def refresh(self):
"""Obtain a new personal-use script type access token."""
self._request_token(grant_type='password', username=self._username,
password=self._password)
18 changes: 18 additions & 0 deletions prawcore/exceptions.py
Expand Up @@ -23,6 +23,24 @@ def __init__(self, response):
.format(response.status_code))


class OAuthException(PrawcoreException):
"""Indicate that there was an OAuth2 related error with the request."""

def __init__(self, response, error, description):
"""OAuthException instances contain the failing response.
:param response: A requests.response instance.
:param error: The error type returned by reddit.
:param description: A description of the error when provided.
"""
self.error = error
self.description = description
self.response = response
PrawcoreException.__init__(self, '{} error processing request ({})'
.format(error, description))


class InsufficientScope(RequestException):
"""Indicate that the request requires a different scope."""

Expand Down

0 comments on commit 0ff6209

Please sign in to comment.