Jean-Michel Provencher Jean-Michel Provencher - 3 months ago 20
Python Question

Authenticate user with a specific hosted domain (hd) in Flask with Oauth2

Hi this is my current python code for authentification in my web app.

auth_flow = OAuth2WebServerFlow(client_id=AUTH_CLIENT_ID,
client_secret=AUTH_CLIENT_SECRET,
scope=AUTH_PLUS_SCOPE,
redirect_uri=AUTH_CALLBACK_URI)

AUTH_ARGS = {
'error': fields.Str(),
'code': fields.Str()
}


@auth_api.route('/', methods=['GET'])
def get_auth_uri():
if current_user and current_user.is_authenticated:
return redirect(LOGIN_PATH)
else:
auth_uri = auth_flow.step1_get_authorize_url()
return redirect(auth_uri)


@auth_api.route('/oauth2callback', methods=['GET'])
@use_kwargs(AUTH_ARGS)
def oauth2_callback(error, code):
if error:
return redirect(url_for('login'), code=HTTPStatus.TEMPORARY_REDIRECT)
else:
try:
authenticate(code)
return redirect(LOGIN_PATH)
except Unauthorized:
raise APIError(HTTPStatus.UNAUTHORIZED, AUTH_FAILED_MESSAGE)


@auth_api.route('/me', methods=['GET'])
@login_required
def get_current_user():
return jsonify(current_user.serialized)


@auth_api.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))



def authenticate(code):
try:
credentials = _get_credentials(code)
user = User.get_or_create(credentials)
login_user(user)
except FlowExchangeError:
raise Unauthorized()


def _get_credentials(code):
return auth_flow.step2_exchange(code)


However, right now, my application is accepting login from any google account adress. I would like to restrict access to login for user with a specified domain like abc@harvard.edu. I've seen some answers with hd parameters but I have no clue how to use it.

Answer

The hd parameter can be set by appending it to the auth_uri as follows

auth_uri = GOOGLE_AUTH_URI
auth_uri = auth_uri + '?hd=' + 'example.com'

auth_flow = OAuth2WebServerFlow(client_id=AUTH_CLIENT_ID,
                            client_secret=AUTH_CLIENT_SECRET,
                            scope=AUTH_PLUS_SCOPE,
                            redirect_uri=AUTH_CALLBACK_URI,
                            auth_uri=auth_uri,
                            )

However in my experience the hd parameter does not restrict users with different email addresses from logging in. You should always validate the credentials.

def authenticate(code):
    try:
        credentials = _get_credentials(code)
        if not credentials.id_token['email'].endswith('@example.com')
            # abort(401)
            raise Unauthorized()
        user = User.get_or_create(credentials)
        login_user(user)
     except FlowExchangeError:
        raise Unauthorized()
Comments