Google OAuth2.0

Google OAuth 2.0 Quick Start

Basic Usage:

oauth_options = {
    "client_id": "<CLIENT_ID>",
    "client_secret": "<CLIENT_SECRET>",
    "redirect_uri": "http://localhost:3000",
    "tablename": "users",
    "email_field": "email",
    "expires_in": 3600,
}

jwt_routes.init_app(app, google_oauth=oauth_options)

Now your front end needs a token. Create an endpoint & return a new access token from the clients header code. For Example:

from flask import request

@app.routes("/login", methods=["POST"])
def login():
    jwt_routes.google.oauth_login(request) # Pass in Flask's request

Now, the next time your front-end requests authorised resources flask-jwt-router will authenticate with this access token until it expires.

Flask-JWT-Router OAuth 2.0 Flow Explained

Client

If you’re client is a React application, we strongly recommend you use React-Google-Oauth2 https://github.com/joegasewicz/react-google-oauth2.0 It’s maintain by Flask-JWT-Router’s author, so if fully compatible.

The client is your front end application, this could be another Flask api that renders jinja2 html templates or a React / Angular / Vue.js single page application. There are 2 steps that your client must successfully complete before Flask-JWT-Router can return a valid Google OAuth 2.0 access token.

  1. The client must redirect the user to Googles sign in page. The user will then be asked to accept any extra scopes (Only required for advance access to Google Apis). If the user successfully signs in then Google will return a code to the client.

  2. The client must now make a POST http request to your Flask api with Google’s code in the X-Auth-Token header. For example

    curl -X POST -H “X-Auth-Token”: “<YOUR_GOOGLE_OAUTH2.0_CODE>” http://localhost:5000/login

Server

The server is your Flask app. Now that your client has a code & has made the request to the server, we must provide a Flask view handler to exchange the client’s code for an access token. Flask-JWT-Router has public method (See oauth_login) that takes Flask’s request as a single argument. If the Google OAuth2.0 code is valid, then a valid access token will be returned in the response body.

For example:

from flask import request

@app.routes("/login", methods=["POST"])
def login():
    data = jwt_routes.google.oauth_login(request) # Pass in Flask's request
    return data, 200

# Returns:
# {
#   "access_token": "GOOGLE_OAUTH2.0_ACCESS_TOKEN>
# }

Each time the client requires any authorised resources in your Flask app, it must make all requests will the following headers:

{
    "X-Auth-Token" : "<YOUR_GOOGLE_OAUTH2.0_CODE>"
}

This will allow the user to gain access to your Flask’s app resources until the access token’s expire time has ended. The client should then decide whether to redirect the user to Google’s login screen.

If your app requires multiple redirect uri’s then you can use the redirect_uri kwarg to assign a uri for the current request handler. For example:

data = jwt_routes.google.oauth_login(request, redirect="http://another_redirect.com")

Testing

Testing OAuth2.0 in a Flask app is non-trivial, especially if you rely on Flask-JWT-Router to append your user onto Flask’s global context (or g). Therefore we have provided a utility method that returns a headers Dict that you can then use in your test view handler request. This example is using the Pytest library:

@pytest.fixture()
def client():
    # See https://flask.palletsprojects.com/en/1.1.x/testing/ for details


def test_blogs(client):
    user_headers = jwt_routes.google.create_test_headers(email="user@gmail.com")
    rv = client.get("/blogs", headers=user_headers)

If you are not running a db in your tests, then you can use the entity kwarg. For example:

# user is an instantiated SqlAlchemy object
user_headers = jwt_routes.google.create_test_headers(email="user@gmail.com", entity=user)
# user_headers: { "X-Auth-Token": "Bearer user@gmail.com" }

If you require more than one request to a Flask view handler in a single unit test, then set the scope kwarg to application. (Default is function). If you are testing different entities within a single unit test method or function then you must pass in your entity. For example:

my_entity = User(email="user@gmail.com") # If you're testing against a real db, make sure this is an entry in the db
_ = jwt_routes.google.create_test_headers(email="user@gmail.com", scope="application", entity=my_entity)
class flask_jwt_router.oauth2.google.Google(http)[source]
authorize(token: str) → Dict[source]

Call to a Google API to authenticate via access_token

client_id: str

Found in https://console.developers.google.com/apis/dashboard > Credentials > OAuth 2.0 Client IDs

client_secret: str

Found in https://console.developers.google.com/apis/dashboard > Credentials > OAuth 2.0 Client IDs Never share this value with any client side code!

email_field: str

Value of the email field column in the

expires_in: int = None

OPTIONAL. Default is 7 days. The lifetime in seconds of the access token. For example, the value “3600” denotes that the access token will expire in one hour from the time the response was generated.

grant_type = 'authorization_code'

As defined in https://tools.ietf.org/html/rfc6749#section-4.1.3 Value MUST be set to “authorization_code”.

header_name: str = 'X-Auth-Token'

The X header name used for the Google Auth2.0 Strategy (subsequent strategies should be “X-<STRATEGY_NAME>-Token”

oauth_login(request: flask_jwt_router.oauth2._base._FlaskRequestType, **kwargs) → Dict[source]
Parameters

request – Flask request object

Key redirect_uri

If your app requires multiple redirect uri’s then

you can use the redirect_uri kwarg to assign a uri for the current request handler. For example:

data = jwt_routes.google.oauth_login(request, redirect="http://another_redirect.com")
Return Dict

redirect_uri: str

This field must match exactly the client side redirect string you have defined in Google developer Credentials page: See https://console.developers.google.com/apis/dashboard > Credentials > OAuth 2.0 Client IDs. Click thru & match from the lists of the redirect domains

tablename: str

Value of SQLAlchemy’s __tablename__ attribute