{"id":15357,"date":"2023-04-19T23:22:05","date_gmt":"2023-04-20T03:22:05","guid":{"rendered":"https:\/\/qxf2.com\/blog\/?p=15357"},"modified":"2023-04-19T23:22:05","modified_gmt":"2023-04-20T03:22:05","slug":"add-google-sso-flask","status":"publish","type":"post","link":"https:\/\/qxf2.com\/blog\/add-google-sso-flask\/","title":{"rendered":"Add Google Sign-In to your Flask app"},"content":{"rendered":"<p>Recently, I integrated SSO with Google Sign-In into a web application using the <a href=\"https:\/\/github.com\/oauthlib\/oauthlib\">oauthlib<\/a> library. While working on this project, I found plenty of resources on SSO and oauthlib separately, but struggled to find a tutorial that could guide me through the setup of Google Sign-In using oauthlib in a timely manner. Therefore, I&#8217;ve written this post to provide a quick guide for those who want to implement the Authorization Code flow for Google Sign-In in Flask applications.<\/p>\n<hr>\n<h4>Would you benefit from reading this post?<\/h4>\n<p>Please note that this post assumes a certain level of familiarity with the topic at hand. While I won&#8217;t be providing an introduction to the basics, I trust that those who are already knowledgeable in this area will find the content useful: <\/p>\n<ul>\n<li><a href=\"https:\/\/auth0.com\/docs\/protocols\/protocol-oauth2\">OAauth2 workflow<\/a><\/li>\n<li>how to generate <a href=\"https:\/\/console.cloud.google.com\/apis\/credentials\">CLIENT ID, CLIENT SECRET  &#038; a Authorized redirect URI from Google developer console<\/a><\/li>\n<li>list of permissions that your application requires(<a href=\"https:\/\/oauth.net\/2\/scope\/\">scope<\/a>)<\/ul>\n<\/li>\n<p>After completing this tutorial, it will be possible for you to integrate a Google sign-in page into your application. The resulting workflow would resemble the following gif<br \/>\n<a href=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/04\/Google_sign_in_post-1.gif\" data-rel=\"lightbox-image-0\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/qxf2.com\/blog\/wp-content\/uploads\/2023\/04\/Google_sign_in_post-1.gif\" alt=\"Google Sign-In to your app workflow\" width=\"2560\" height=\"1404\" class=\"aligncenter size-full wp-image-18203\" \/><\/a><\/p>\n<hr>\n<h4>Implement Google sign-in:<\/h4>\n<p>To follow the steps in this section, you&#8217;ll need to have already generated a <code>CLIENT_ID<\/code>, <code>CLIENT_SECRET<\/code>, and <code>redirect_uri<\/code>, and have decided on the <code>resource<\/code> (in our case, email) that you&#8217;ll be requesting for your application. Once you have these details, implementing Google Sign-In in a Flask app is just a matter of two simple steps:<\/p>\n<ol>\n<li>Generate a Google Sign-In URI, route the users to this Sign-In page from your landing page<\/li>\n<li>Redirect the user to a success page after they have successfully logged in using their Google credentials<\/li>\n<\/ol>\n<h5>1. Generate a Google Sign-In URI, route the users to this Sign-In page from your landing page<\/h5>\n<p>Create a landing page like the above image with Google Sign-In URI using <code>oauthlib<\/code>, this login page will prompt the users to enter their Google username and password.<\/p>\n<pre lang=\"python\">\r\nCLIENT_ID = os.environ['CLIENT_ID']\r\nCLIENT_SECRET = os.environ['CLIENT_SECRET']\r\n\r\nDATA = {\r\n        'response_type':\"code\", # this tells the auth server that we are invoking authorization workflow\r\n        'redirect_uri':\"https:\/\/localhost:5000\/home\", # redirect URI https:\/\/console.developers.google.com\/apis\/credentials\r\n        'scope': 'https:\/\/www.googleapis.com\/auth\/userinfo.email', # resource we are trying to access through Google API\r\n        'client_id':CLIENT_ID, # client ID from https:\/\/console.developers.google.com\/apis\/credentials\r\n        'prompt':'consent'} # adds a consent screen\r\n\r\nURL_DICT = {\r\n        'google_oauth' : 'https:\/\/accounts.google.com\/o\/oauth2\/v2\/auth', # Google OAuth URI\r\n        'token_gen' : 'https:\/\/oauth2.googleapis.com\/token', # URI to generate token to access Google API\r\n        'get_user_info' : 'https:\/\/www.googleapis.com\/oauth2\/v3\/userinfo' # URI to get the user info\r\n        }\r\n\r\n# Create a Sign in URI\r\nCLIENT = oauth2.WebApplicationClient(CLIENT_ID)\r\nREQ_URI = CLIENT.prepare_request_uri(\r\n    uri=URL_DICT['google_oauth'],\r\n    redirect_uri=DATA['redirect_uri'],\r\n    scope=DATA['scope'],\r\n    prompt=DATA['prompt'])\r\n<\/pre>\n<p>Lets create a Flask view function to land the users on the Sign-In page<\/p>\n<pre lang=\"python\">\r\n@app.route('\/')\r\ndef login():\r\n    \"Home\"\r\n    # redirect to the newly created Sign-In URI\r\n    return redirect(REQ_URI)\r\n<\/pre>\n<h5>2. Redirect to success page after successfully logging in using Google credentials<\/h5>\n<p>Lets create a home route function that implements a page like the above image that redirects to redirect_uri set when generating CLIENT_ID and CLIENT_SECRET<\/p>\n<pre lang=\"python\">\r\n@app.route('\/home')\r\ndef home():\r\n    \"Redirect after Google login & consent\"\r\n\r\n    # Get the code after authenticating from the URL\r\n    code = request.args.get('code')\r\n\r\n    # Generate URL to generate token\r\n    token_url, headers, body = CLIENT.prepare_token_request(\r\n            URL_DICT['token_gen'],\r\n            authorisation_response=request.url,\r\n            # request.base_url is same as DATA['redirect_uri']\r\n            redirect_url=request.base_url,\r\n            code=code)\r\n\r\n    # Generate token to access Google API\r\n    token_response = requests.post(\r\n            token_url,\r\n            headers=headers,\r\n            data=body,\r\n            auth=(CLIENT_ID, CLIENT_SECRET))\r\n\r\n    # Parse the token response\r\n    CLIENT.parse_request_body_response(json.dumps(token_response.json()))\r\n\r\n    # Add token to the  Google endpoint to get the user info\r\n    # oauthlib uses the token parsed in the previous step\r\n    uri, headers, body = CLIENT.add_token(URL_DICT['get_user_info'])\r\n\r\n    # Get the user info\r\n    response_user_info = requests.get(uri, headers=headers, data=body)\r\n    info = response_user_info.json()\r\n\r\n    return redirect('\/user\/%s' % info['email'])\r\n<\/pre>\n<p>Lets create a login_success function to redirect the user to a dynamic page with the user&#8217;s email<\/p>\n<pre lang=\"python\">\r\n@app.route('\/user\/<email>')\r\ndef login_success(email):\r\n    \"Landing page after successful login\"\r\n\r\n    return \"Hello %s\" % email\r\n<\/pre>\n<h5>Putting it all together<\/h5>\n<pre lang=\"python\">\r\n#!\/usr\/bin\/env python3\r\n\"\"\"\r\nA Flask app for Google SSO\r\n\"\"\"\r\n\r\nimport json\r\nimport os\r\nimport requests\r\nfrom flask import Flask, redirect, request\r\nfrom  oauthlib import oauth2\r\n\r\nCLIENT_ID = os.environ['CLIENT_ID']\r\nCLIENT_SECRET = os.environ['CLIENT_SECRET']\r\n\r\nDATA = {\r\n        'response_type':\"code\", # this tells the auth server that we are invoking authorization workflow\r\n        'redirect_uri':\"https:\/\/localhost:5000\/home\", # redirect URI https:\/\/console.developers.google.com\/apis\/credentials\r\n        'scope': 'https:\/\/www.googleapis.com\/auth\/userinfo.email', # resource we are trying to access through Google API\r\n        'client_id':CLIENT_ID, # client ID from https:\/\/console.developers.google.com\/apis\/credentials\r\n        'prompt':'consent'} # adds a consent screen\r\n\r\nURL_DICT = {\r\n        'google_oauth' : 'https:\/\/accounts.google.com\/o\/oauth2\/v2\/auth', # Google OAuth URI\r\n        'token_gen' : 'https:\/\/oauth2.googleapis.com\/token', # URI to generate token to access Google API\r\n        'get_user_info' : 'https:\/\/www.googleapis.com\/oauth2\/v3\/userinfo' # URI to get the user info\r\n        }\r\n\r\n# Create a Sign in URI\r\nCLIENT = oauth2.WebApplicationClient(CLIENT_ID)\r\nREQ_URI = CLIENT.prepare_request_uri(\r\n    uri=URL_DICT['google_oauth'],\r\n    redirect_uri=DATA['redirect_uri'],\r\n    scope=DATA['scope'],\r\n    prompt=DATA['prompt'])\r\n\r\napp = Flask(__name__)\r\n\r\n@app.route('\/')\r\ndef login():\r\n    \"Home\"\r\n    # redirect to the newly created Sign-In URI\r\n    return redirect(REQ_URI)\r\n\r\n@app.route('\/home')\r\ndef home():\r\n    \"Redirect after Google login & consent\"\r\n\r\n    # Get the code after authenticating from the URL\r\n    code = request.args.get('code')\r\n\r\n    # Generate URL to generate token\r\n    token_url, headers, body = CLIENT.prepare_token_request(\r\n            URL_DICT['token_gen'],\r\n            authorisation_response=request.url,\r\n            # request.base_url is same as DATA['redirect_uri']\r\n            redirect_url=request.base_url,\r\n            code=code)\r\n\r\n    # Generate token to access Google API\r\n    token_response = requests.post(\r\n            token_url,\r\n            headers=headers,\r\n            data=body,\r\n            auth=(CLIENT_ID, CLIENT_SECRET))\r\n\r\n    # Parse the token response\r\n    CLIENT.parse_request_body_response(json.dumps(token_response.json()))\r\n\r\n    # Add token to the  Google endpoint to get the user info\r\n    # oauthlib uses the token parsed in the previous step\r\n    uri, headers, body = CLIENT.add_token(URL_DICT['get_user_info'])\r\n\r\n    # Get the user info\r\n    response_user_info = requests.get(uri, headers=headers, data=body)\r\n    info = response_user_info.json()\r\n\r\n    return redirect('\/user\/%s' % info['email'])\r\n\r\n@app.route('\/user\/<email>')\r\ndef login_success(email):\r\n    \"Landing page after successful login\"\r\n\r\n    return \"Hello %s\" % email\r\n\r\nif __name__ == '__main__':\r\n    app.run(debug=True, host='0.0.0.0', port=5000, ssl_context='adhoc')\r\n<\/pre>\n<p>To view this project on GitHub, simply follow this link: <a href=\"https:\/\/github.com\/shivahari\/sso_google_oauthlib\">sso_google_oauthlib<\/a><\/p>\n<p>That&#8217;s it! With this tutorial, you can easily integrate a Google Sign-In page into your Flask application<\/p>\n<hr>\n<h5>Hire Qxf2 for your testing needs<\/h5>\n<p>Modern stacks need modern testing. <a href=\"https:\/\/qxf2.com\/contact?utm_source=google_sso&#038;utm_medium=click&#038;utm_campaign=From%20blog\">Contact Qxf2<\/a> to work with expert technical testers. Our testers go well beyond traditional test automation. We can help your teams test infrastructure maintained as code, add several types of tests to your data pipelines, integrate deep testing into your MLOPs cycle and so much more!<\/p>\n<hr>\n","protected":false},"excerpt":{"rendered":"<p>Recently, I integrated SSO with Google Sign-In into a web application using the oauthlib library. While working on this project, I found plenty of resources on SSO and oauthlib separately, but struggled to find a tutorial that could guide me through the setup of Google Sign-In using oauthlib in a timely manner. Therefore, I&#8217;ve written this post to provide a [&hellip;]<\/p>\n","protected":false},"author":9,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[172,338,337],"tags":[],"class_list":["post-15357","post","type-post","status-publish","format-standard","hentry","category-flask","category-oauth","category-sso"],"_links":{"self":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15357","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/users\/9"}],"replies":[{"embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/comments?post=15357"}],"version-history":[{"count":60,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15357\/revisions"}],"predecessor-version":[{"id":18236,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/posts\/15357\/revisions\/18236"}],"wp:attachment":[{"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/media?parent=15357"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/categories?post=15357"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/qxf2.com\/blog\/wp-json\/wp\/v2\/tags?post=15357"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}