diff --git a/README b/README
index 8b1af68..5590886 100644
--- a/README
+++ b/README
@@ -13,6 +13,7 @@ Supported providers out of the box:
- foursquare (OAuth 2.0)
- Twitter (OAuth 1.0a)
- LinkedIn (OAuth 1.0a)
+ - Flickr (OAuth 1.0a)
- OpenID, using App Engine users module API
Dependencies:
@@ -186,6 +187,18 @@ versions, say one on localhost and another on example.org, you'll probably
want to register two applications (e.g. "dev" and "production") and use
appropriate set of key/secret accordingly.
+== Flickr
+Docs: http://www.flickr.com/services/api/auth.oauth.html
+Get client/secret: http://www.flickr.com/services/apps/create/apply/
+
+Scopes are not supported. This is OAuth 1.0a. However, Flickr requires a 'perms' parameter
+read/write/delete which is set in secrets.py
+
+Callback URL is required when setting up your flickr app. So, if you have two
+versions, say one on localhost and another on example.org, you'll probably
+want to register two applications (e.g. "dev" and "production") and use
+appropriate set of key/secret accordingly.
+
CSRF protection
================
diff --git a/example/handlers.py b/example/handlers.py
index 0912ec6..a04e41a 100644
--- a/example/handlers.py
+++ b/example/handlers.py
@@ -119,6 +119,11 @@ class AuthHandler(BaseRequestHandler, SimpleAuthHandler):
'first-name' : 'name',
'public-profile-url': 'link'
},
+ 'flickr' : {
+ 'buddy_icon_url' : 'avatar_url',
+ 'username' : 'name',
+ 'link': 'link'
+ },
'foursquare' : {
'photo' : lambda photo: ('avatar_url', photo.get('prefix') + '100x100' + photo.get('suffix')),
'firstName': 'firstName',
diff --git a/example/secrets.py.template b/example/secrets.py.template
index 1250f30..d49de55 100644
--- a/example/secrets.py.template
+++ b/example/secrets.py.template
@@ -1,3 +1,9 @@
+import os
+import logging
+
+DEBUG = os.environ['SERVER_SOFTWARE'].startswith('Dev')
+logging.info("Starting application in DEBUG mode: %s", DEBUG)
+
# Copy this file into secrets.py and set keys, secrets and scopes.
# This is a session secret key used by webapp2 framework.
@@ -31,6 +37,13 @@ TWITTER_CONSUMER_SECRET = 'oauth1.0a consumer secret'
FOURSQUARE_CLIENT_ID = 'client id'
FOURSQUARE_CLIENT_SECRET = 'client secret'
+# Flickr APIs
+#http://www.flickr.com/services/apps/create/apply/
+FLICKR_CONSUMER_KEY = 'oauth1.0a consumer dev key' if DEBUG else 'oauth1.0a consumer key'
+FLICKR_CONSUMER_SECRET = 'oauth1.0a consumer dev secret' if DEBUG else 'oauth1.0a consumer secret'
+#read, write, or delete
+FLICKR_CONSUMER_PERMS = 'read'
+
# config that summarizes the above
AUTH_CONFIG = {
# OAuth 2.0 providers
@@ -44,8 +57,9 @@ AUTH_CONFIG = {
'authorization_code'),
# OAuth 1.0 providers don't have scopes
- 'twitter' : (TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET),
- 'linkedin' : (LINKEDIN_CONSUMER_KEY, LINKEDIN_CONSUMER_SECRET),
+ 'twitter' : (TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, ''),
+ 'flickr' : (FLICKR_CONSUMER_KEY, FLICKR_CONSUMER_SECRET, FLICKR_CONSUMER_PERMS),
+ 'linkedin' : (LINKEDIN_CONSUMER_KEY, LINKEDIN_CONSUMER_SECRET, ''),
# OpenID doesn't need any key/secret
}
diff --git a/example/templates/home.html b/example/templates/home.html
index a3f64e2..58a912d 100644
--- a/example/templates/home.html
+++ b/example/templates/home.html
@@ -15,5 +15,6 @@
LinkedIn
Windows Live
foursquare
+ Flickr
{% endif %}
{% endblock %}
diff --git a/simpleauth/handler.py b/simpleauth/handler.py
index 9cb0ccb..cf9e4e0 100644
--- a/simpleauth/handler.py
+++ b/simpleauth/handler.py
@@ -89,6 +89,10 @@ class SimpleAuthHandler(object):
'request': 'https://api.twitter.com/oauth/request_token',
'auth' : 'https://api.twitter.com/oauth/authenticate?{0}'
}, 'https://api.twitter.com/oauth/access_token'),
+ 'flickr' : ('oauth1', {
+ 'request': 'http://www.flickr.com/services/oauth/request_token',
+ 'auth' : 'http://www.flickr.com/services/oauth/authorize?{0}'
+ }, 'http://www.flickr.com/services/oauth/access_token'),
'foursquare': ('oauth2',
'https://foursquare.com/oauth2/authenticate?{0}',
'https://foursquare.com/oauth2/access_token'),
@@ -102,7 +106,8 @@ class SimpleAuthHandler(object):
'foursquare' : '_json_parser',
'facebook' : '_query_string_parser',
'linkedin' : '_query_string_parser',
- 'twitter' : '_query_string_parser'
+ 'twitter' : '_query_string_parser',
+ 'flickr' : '_query_string_parser'
}
# Set this to True in your handler if you want to use
@@ -233,7 +238,7 @@ def _oauth2_callback(self, provider, access_token_url):
def _oauth1_init(self, provider, auth_urls):
"""Initiates OAuth 1.0 dance"""
- key, secret = self._get_consumer_info_for(provider)
+ key, secret, perms = self._get_consumer_info_for(provider)
callback_url = self._callback_uri_for(provider)
token_request_url = auth_urls.get('request', None)
auth_url = auth_urls.get('auth', None)
@@ -252,11 +257,17 @@ def _oauth1_init(self, provider, auth_urls):
if not request_token.get('oauth_token', None):
raise AuthProviderResponseError(
"Couldn't get a request token from %s" % str(request_token), provider)
-
- target_url = auth_urls['auth'].format(urlencode({
- 'oauth_token': request_token.get('oauth_token', None),
- 'oauth_callback': callback_url
- }))
+
+ params = {
+ 'oauth_token': request_token.get('oauth_token', None),
+ 'oauth_callback': callback_url,
+ 'perms': (perms, None)
+ }
+
+ if perms:
+ params.update(perms=perms)
+
+ target_url = auth_urls['auth'].format(urlencode(params))
logging.debug('Redirecting user to %s', target_url)
@@ -276,7 +287,7 @@ def _oauth1_callback(self, provider, access_token_url):
raise AuthProviderResponseError(
"No OAuth verifier was provided", provider)
- consumer_key, consumer_secret = self._get_consumer_info_for(provider)
+ consumer_key, consumer_secret, consumer_perms = self._get_consumer_info_for(provider)
token = oauth1.Token(request_token['oauth_token'],
request_token['oauth_token_secret'])
token.set_verifier(verifier)
@@ -448,6 +459,26 @@ def _get_twitter_user_info(self, auth_info, key=None, secret=None):
uinfo = json.loads(content)
uinfo.setdefault('link', 'http://twitter.com/%s' % uinfo['screen_name'])
return uinfo
+
+ def _get_flickr_user_info(self, auth_info, key=None, secret=None):
+ """Returns a dict of twitter user using
+ https://api.twitter.com/1/account/verify_credentials.json
+ """
+ token = oauth1.Token(key=auth_info['oauth_token'],
+ secret=auth_info['oauth_token_secret'])
+ client = self._oauth1_client(token, key, secret)
+
+ resp, content = client.request(
+ 'http://api.flickr.com/services/rest?format=json&nojsoncallback=1&method=flickr.people.getInfo&user_id=%s' % auth_info['user_nsid']
+ )
+ uinfo = json.loads(content)
+ uinfo.setdefault('link', uinfo['person']['profileurl']['_content'])
+ uinfo.setdefault('id', uinfo['person']['id'])
+ uinfo.setdefault('username', uinfo['person']['username']['_content'])
+ uinfo.setdefault('buddy_icon_url', 'http://farm%s.staticflickr.com/%s/buddyicons/%s.jpg'
+ % (uinfo['person']['iconfarm'],uinfo['person']['iconserver'], uinfo['person']['id']))
+
+ return uinfo
#
# aux methods