-
Notifications
You must be signed in to change notification settings - Fork 16
Writing a Provider Class (draft)
Implementing a new provider for foauth.org can be as simple as create a class that contains some key pieces of information about the provider. From there, foauth.org will be able to do the rest of the integration and functionality behind the scenes. Some providers will be more complicated than that, but let's start with the easy stuff.
foauth.org supports OAuth 1 and OAuth 2 by providing a base class for each the provides the necessary functionality. They both also share a common base that handles overall integration with the site, but each is designed for its specific version of the specification. The provider you're implementing should be very clear about what version it uses, so this should be an easy choice. Just import the providers module and subclass the appropriate base class.
import foauth.providers
class Example(foauth.providers.OAuth1):
pass
The first few attributes of your new class are general details about the provider, rather than anything specific to OAuth. These are simply strings assigned as class attributes, two of which are required:
-
provider_url: the URL of the provider's main website. This allows users to find out what a service is all about before trying to authorize it. -
docs_url: the URL of the provider's API documentation. Ideally, this would jump straight to the URL endpoints, but the root of the API documentation is also acceptable.
In addition, a few other pieces of information are implied from the name you give the class itself. If these don't line up right for any reason (such as Python's lack of punctuation in names), you can specify them directly as class attributes:
-
name: the name of the provider. This will normally be the same as the name of the class, but for services like last.fm, the class name can't accurately reflect the name that should be displayed on the site. This class variable allows you to specify it explicitly. -
alias: a unique alias for the provider, which will be used in URLs. This will default to a lower-case version of the class name, but for services like 500px, which begin with a number, it can be specified explicitly.
Every OAuth provider exposes some URLs that are used during the authorization process; OAuth 1 uses three URLs, while OAuth 2 only uses two. These URLs must be specified in the class in order for the authorization process to work at all:
-
request_token_url: the URL where foauth.org can retrieve a temporary request token. OAuth 1 only. -
authorize_url: the URL the user will see in order to decide whether to grant access to the service. -
access_token_url: the URL where foauth.org will retrieve a usable access token.
In addition to the OAuth-specific URLs, every provider will have a series of API endpoints available, which are used to communicate with the service. These will typically be under a single domain, which must be added to the class definition in order to help foauth.org route requests to the right service and also communicate with that service.
-
api_domain: a fully-qualified domain name indicating where API endpoints can be found. It must contain only the domain name; any additional parts of the path will simply be passed through when making requests.
Some services will actually have API endpoints multiple domains, even though they all use the same access token. For example, Dropbox uses api.dropbox.com for general metadata requests, while api-content.dropbox.com is used for actual file transfer operations. So instead of using api_domain:
-
api_domains: a list of fully-qualified domain names indicating where API endpoints can be found. Each entry will work identically to theapi_domainattribute above; this simply allows more than one of them.
In fact, api_domain internally gets added to a single-item list and assigned to api_domains, which foauth.org then uses exclusively.
Every service must have at least one permission listed in the class, which will be displayed to the user.
-
available_permissions: a list of 2-tuples describing the permissions available for the service. The first item in each tuple is a string that the service uses to refer to that service, while the second item is a human-readable description of the permission. For the basic, default permissions that every authorization will have, useNoneinstead of a string.
In OAuth 2 terminology, these are scopes. OAuth 1 didn't natively allow for granular permissions like this, so most OAuth 1 providers will have only a None permission describing the overall capabilities of the service.
Examples:
available_permissions = [
(None, 'read and write to your photos and videos'),
]
or:
available_permissions = [
(None, 'read your public profile information'),
('write', 'write to your public profile information'),
('private', 'read and write to your private messages'),
]
import foauth.providers
class Twitter(foauth.providers.OAuth1):
# General info about the provider
provider_url = 'https://www.twitter.com/'
docs_url = 'https://dev.twitter.com/docs'
# URLs to interact with the API
request_token_url = 'https://api.twitter.com/oauth/request_token'
authorize_url = 'https://api.twitter.com/oauth/authorize'
access_token_url = 'https://api.twitter.com/oauth/access_token'
api_domain = 'api.twitter.com'
available_permissions = [
(None, 'read and send tweets, including DMs'),
]
import foauth.providers
class Meetup(foauth.providers.OAuth2):
# General info about the provider
provider_url = 'http://www.meetup.com/'
docs_url = 'http://www.meetup.com/meetup_api/'
# URLs to interact with the API
authorize_url = 'https://secure.meetup.com/oauth2/authorize'
access_token_url = 'https://secure.meetup.com/oauth2/access'
api_domain = 'api.meetup.com'
available_permissions = [
(None, 'access your groups, create and edit events, and post photos'),
('messaging', 'send and receive messages'),
('ageless', 'keep the authorization active for two weeks'),
]
bearer_type = foauth.providers.BEARER_URI
For many services, the sections above are all you need in order to interact with the provider. Others, however, may use old versions of the spec or deviate in other — sometimes unusual — ways. To allow for this, subclasses of OAuth1 and OAuth2 can override the default behavior at certain points.
In the case of last.fm, there are enough overrides available to support services that don't even use OAuth! Their process is similar enough that the overall flow is compatible with OAuth, so with enough overrides, foauth.org can still support it.
Some overrides are as simple as adding more attributes to the class:
-
https = False: by default, foauth.org will always send API traffic to providers using HTTPS. Some services, however, don't have that capability and will only respond on an unsecure connection. In those cases, setting this flag toFalsewill tell foauth.org not to try to use HTTPS at all.