async def auth_handler(request): session = await get_session(request) params = urllib.parse.parse_qs(request.query_string) user = session.get('User') if user: # Already authenticated request['user'] = user elif handler in whitelist_handlers: # We don't need authentication pass elif handler == handle_github_callback and \ session.get('github_state'): # Attempting to authenticate - let them pass through pass elif api_unauthorized and request.path.startswith('/api/'): return web.HTTPUnauthorized() else: gh = GithubClient(client_id=gh_id, client_secret=gh_secret) state = os.urandom(30).hex() authorize_url = gh.get_authorize_url( scope='user:email read:org', state=state) session['github_state'] = state session['desired_location'] = request.path return web.HTTPFound(authorize_url) return await handler(request)
async def test_oauth2(http, response): from aioauth_client import GithubClient, ClientRegistry github = GithubClient(client_id='cid', client_secret='csecret') assert github assert 'github' in ClientRegistry.clients assert github.get_authorize_url( ) == 'https://github.com/login/oauth/authorize?client_id=cid&response_type=code' # noqa http.return_value = response(json={'access_token': 'TEST-TOKEN'}) token, meta = await github.get_access_token('000') assert token == 'TEST-TOKEN' assert meta assert http.called http.reset_mock() http.return_value = response(json={'access_token': 'TEST-TOKEN'}) res = await github.request('GET', 'user', access_token='NEW-TEST-TOKEN') assert res http.assert_called_with( 'GET', 'https://api.github.com/user', params=None, headers={ 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'Authorization': 'Bearer NEW-TEST-TOKEN' })
async def auth_handler(request): session = await get_session(request) params = urllib.parse.parse_qs(request.query_string) user = session.get('User') if user: # Already authenticated request['user'] = user elif handler in whitelist_handlers: # We don't need authentication pass elif handler == handle_github_callback and \ session.get('github_state'): # Attempting to authenticate - let them pass through pass elif api_unauthorized and request.path.startswith('/api/'): return web.HTTPUnauthorized() else: gh = GithubClient( client_id=gh_id, client_secret=gh_secret ) state = os.urandom(30).hex() authorize_url = gh.get_authorize_url( scope='user:email read:org', state=state) session['github_state'] = state session['desired_location'] = request.path return web.HTTPFound(authorize_url) return await handler(request)
class GithubAuth: def __init__(self, client_id, client_secret): self.client_id = client_id self.__client_secret = client_secret self.client = GithubClient(client_id, client_secret) def auth_url(self): # user:email might be enough here return self.client.get_authorize_url(scope="user") async def get_token(self, code): return await self.client.get_access_token(code) def api(self, token): return GithubAPI(token)
async def github(request): github = GithubClient( client_id='b6281b6fe88fa4c313e6', client_secret='21ff23d9f1cad775daee6a38d230e1ee05b04f7c', ) if 'code' not in request.url.query: return ResponseRedirect(github.get_authorize_url(scope='user:email')) # Get access token code = request.url.query['code'] token, _ = await github.get_access_token(code) assert token # Get a resource `https://api.github.com/user` response = await github.request('GET', 'user') return await response.read()
def github(request): github = GithubClient( client_id='b6281b6fe88fa4c313e6', client_secret='21ff23d9f1cad775daee6a38d230e1ee05b04f7c', ) if 'code' not in request.GET: return web.HTTPFound(github.get_authorize_url(scope='user:email')) # Get access token code = request.GET['code'] token = yield from github.get_access_token(code) # Get a resource response = yield from github.request('GET', 'user') body = yield from response.read() return web.Response(body=body, content_type='application/json')
def github(request): github = GithubClient( client_id='b6281b6fe88fa4c313e6', client_secret='21ff23d9f1cad775daee6a38d230e1ee05b04f7c', ) if 'code' not in request.query: return web.HTTPFound(github.get_authorize_url(scope='user:email')) # Get access token code = request.query['code'] token, _ = yield from github.get_access_token(code) assert token # Get a resource `https://api.github.com/user` response = yield from github.request('GET', 'user') body = yield from response.read() return web.Response(body=body, content_type='application/json')
async def github_auth(request): github = GithubClient( client_id=config.GITHUB_CLIENT_ID, client_secret=config.GITHUB_CLIENT_SECRET, ) session = await aiohttp_session.get_session(request) if 'code' not in request.query: redirect_uri = request.query.get('redirect_uri', '/') session['redirect_uri'] = redirect_uri return web.HTTPFound(github.get_authorize_url(scope='user:email')) code = request.query['code'] token, _ = await github.get_access_token(code) session['token'] = token next_uri = session.pop('redirect_uri', '/') logger.debug('Redirecting back to %s', next_uri) return web.HTTPFound(next_uri)
class User(BaseUser): method = "github" routes = web.RouteTableDef() def __init__(self, redirect_uri, code_challenge): super().__init__(redirect_uri, code_challenge) if not GITHUB_CLIENT_ID or not GITHUB_CLIENT_SECRET: raise Exception("GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET should be set via environment") self._github = GithubClient(client_id=GITHUB_CLIENT_ID, client_secret=GITHUB_CLIENT_SECRET) def get_authorize_page(self): # Chance on collision is really low, but would be really annoying. So # simply protect against it by looking for an unused UUID. state = secrets.token_hex(16) while state in _github_states: state = secrets.token_hex(16) self._state = state _github_states[self._state] = self # We don't set any scope, as we only want the username + id authorize_url = self._github.get_authorize_url(state=self._state) return web.HTTPFound(location=authorize_url) @staticmethod def get_by_state(state): if state not in _github_states: return None user = _github_states[state] user._forget_github_state() return user def logout(self): self._forget_github_state() super().logout() def _forget_github_state(self): if self._state: del _github_states[self._state] self._state = None async def get_user_information(self, code): # Validate the code and fetch the user info await self._github.get_access_token(code) user, _ = await self._github.user_info() self.display_name = user.username self.id = str(user.id) @staticmethod @routes.get("/user/github-callback") async def login_github_callback(request): code = in_query_github_code(request.query.get("code")) state = in_query_github_state(request.query.get("state")) user = User.get_by_state(state) if user is None: return web.HTTPNotFound() await user.get_user_information(code) return web.HTTPFound(location=f"{user.redirect_uri}?code={user.code}") @staticmethod def get_description(): return "Login via GitHub" @staticmethod def get_settings_url(): return f"https://github.com/settings/connections/applications/{GITHUB_CLIENT_ID}"
async def get_oauth_url(self, request, session, state): gh = GithubClient(client_id=self._id, client_secret=self._secret) authorize_url = gh.get_authorize_url(scope='user:email read:org', state=state) return authorize_url