OAuth Authentication with Flask

Posted by
on under

Many web sites offer users the option to use a streamlined single-click registration and login built on third party authentication services, typically run by the big social networks. In this article I want to give you an introduction to the OAuth protocol, which is one of the most used third-party authentication mechanism. I will also show you a complete Flask application that implements "Sign In with Facebook" and "Sign In with Twitter" functionality. With these two implementations as a guide you should find it easy to add any other OAuth providers you may need.

Brief Introduction to OAuth

The best way to explain OAuth is by going over the list of events that occur during the sign in process:

  1. The user navigates to the application's home page, say http://www.example.com, and clicks the "Sign in with Facebook" button, which links to an application route, for example http://www.example.com/authorize/facebook.
  2. The server receives the request and responds with a redirect to Facebook's OAuth authorization URL. All OAuth providers must document a URL to redirect the user to.
  3. The user is now prompted to login to Facebook (if not logged in already). Then a request to share information is presented, where the user needs to give Facebook permission to share the requested information with the originating application. This is all done at Facebook's website and is a private transaction between Facebook and the user, the application does not participate.
  4. Once the user accepts the request to share information, Facebook redirects back to the application at a pre-configured callback URL, for example http://www.example.com/callback/facebook. The query string of the redirect URL includes an authorization code that the application can use to access the Facebook API on behalf of the user.
  5. The application uses the Facebook API to obtain user information. Of particular interest is a unique identifier for the user, which can be used to register the user in the application's database, and once the user is registered to perform a login.

You can see above that the exchange between the application and the third party service is not trivial, but for the user it is extremely simple, since all the user needs to do is log in to the third party site and give permission to share information with the application.

There are two versions of the OAuth protocol currently in use, both following the overall process described above but with some implementation differences. OAuth 1.0a, used by Twitter, is the most complex of the two. OAuth 2, used by Facebook, is a backwards incompatible revision of the protocol that eliminates much of the complexity of version 1.0a by relying on secure HTTP for encryption.

Registration with OAuth Providers

Before an application can use a third party OAuth provider it needs to register with it. For Facebook and Twitter this is done on their respective developer sites with the creation of an "app" that represents the application for users of these sites.

To create a Facebook app you can visit https://developer.facebook.com. Select "Add a New App" from the Apps dropdown, and make the type "WWW/Website". Then enter a name and category for your app. Once the application is created, go to the "App Configuration" section and set the URL of the application, which in the case of you running it on your own computer will be http://localhost:5000.

For Twitter the location is https://apps.twitter.com. You will be asked to provide the app name, description, website and callback URL. For the last two you can enter placeholders, for example http://example.com and http://example.com/callback/twitter.

Note: If you want to use other OAuth providers you will need to find the appropriate procedure to register an application in their developer documentation.

The newly created app will be assigned two codes, usually called "id" and "secret". These identify the application that is making the authentication request, and are passed in the query string of the redirect URL to the provider site, in step 2 above.

OAuth Authentication Example

In the following sections I'm going to describe a relatively simple Flask application that implements Facebook and Twitter authentication.

I'm only going to show you the important parts of the application in the article, but the complete application is available on this GitHub repository: https://github.com/miguelgrinberg/flask-oauth-example. At the end of this article I show you the instructions on how to run it.

User Model

The users of the example application are stored in a SQLAlchemy database. The application uses the Flask-SQLAlchemy extension to work with the database, and the Flask-Login extension to keep track of logged in users.

from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin

db = SQLAlchemy(app)
lm = LoginManager(app)

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    social_id = db.Column(db.String(64), nullable=False, unique=True)
    nickname = db.Column(db.String(64), nullable=False)
    email = db.Column(db.String(64), nullable=True)

@lm.user_loader
def load_user(id):
    return User.query.get(int(id))

The database has a single table for the users. In addition to the id that is the primary key, the users table contains three columns:

  • social_id: a string that defines a unique identifier from the third party authentication service used to login.
  • nickname: a nickname for the user. Must be defined for all users, and does not need to be unique.
  • email: the email address of the user. This column is optional.

The model also inherits from UserMixin from Flask-Login, as that gives it the methods required by that extension. The user_loader callback function, also required by Flask-Login, loads a user by its primary key.

OAuth Implementation

There are several OAuth client packages for Python. For this example I have decided to use Rauth. But even when using an OAuth package, there are many aspects of the authentication against OAuth service providers that are left up to each provider to implement, which makes the task harder.

First of all, there are the two versions of the OAuth protocol, both widely used. But even among different providers using the same OAuth version, there are many details that are not part of the specification and need to be done according to the provider's own documentation.

For this reason I have decided to implement an abstraction layer on top of Rauth, so that the Flask application can be written generically. Below you can see a simple base class under which the provider specific implementations will be written:

class OAuthSignIn(object):
    providers = None

    def __init__(self, provider_name):
        self.provider_name = provider_name
        credentials = current_app.config['OAUTH_CREDENTIALS'][provider_name]
        self.consumer_id = credentials['id']
        self.consumer_secret = credentials['secret']

    def authorize(self):
        pass

    def callback(self):
        pass

    def get_callback_url(self):
        return url_for('oauth_callback', provider=self.provider_name,
                       _external=True)

    @classmethod
    def get_provider(self, provider_name):
        if self.providers is None:
            self.providers = {}
            for provider_class in self.__subclasses__():
                provider = provider_class()
                self.providers[provider.provider_name] = provider
        return self.providers[provider_name]

class FacebookSignIn(OAuthSignIn):
    pass

class TwitterSignIn(OAuthSignIn):
    pass

The OAuthSignIn base class defines the structure that the subclasses that implement each provider must follow. The constructor initializes the provider's name, and the application id and secret assigned by it, which are obtained from the configuration. Below you can see how the example application is configured (of course you will need to replace these codes with your own when you try this application):

app.config['OAUTH_CREDENTIALS'] = {
    'facebook': {
        'id': '470154729788964',
        'secret': '010cc08bd4f51e34f3f3e684fbdea8a7'
    },
    'twitter': {
        'id': '3RzWQclolxWZIMq5LJqzRZPTl',
        'secret': 'm9TEd58DSEtRrZHpz2EjrV9AhsBRxKMo8m3kuIZj3zLwzwIimt'
    }
}

At a high level there are two significant events supported by this class that are common to all OAuth providers:

  1. Initiation of the authentication process. For this the application needs to redirect to the provider's web site to let the user authenticate there. This is represented by the authorize() method.
  2. Once the authentication is completed the provider redirects back to the application. This is handled in the callback() method. Since the provider does not have direct access to the internal methods of the application, it will be redirecting to a URL that will call it. The URL that the provider needs to redirect to is returned by the get_callback_url() method and is built using the provider name, so that each provider gets its own dedicated route.

The get_provider() class method is used to lookup the correct OAuthSignIn instance given a provider name. This method uses introspection to find all the OAuthSignIn subclasses, and then saves an instance of each in a dictionary.

OAuth Authentication with Rauth

Rauth represent OAuth providers with an object of class OAuth1Service or OAuth2Service, depending on the version of the protocol that it uses. I create an object of this class in each provider's OAuthSignIn subclass. The implementations for Facebook and Twitter are shown below:

class FacebookSignIn(OAuthSignIn):
    def __init__(self):
        super(FacebookSignIn, self).__init__('facebook')
        self.service = OAuth2Service(
            name='facebook',
            client_id=self.consumer_id,
            client_secret=self.consumer_secret,
            authorize_url='https://graph.facebook.com/oauth/authorize',           
            access_token_url='https://graph.facebook.com/oauth/access_token',
            base_url='https://graph.facebook.com/'
        )

class TwitterSignIn(OAuthSignIn):
    def __init__(self):
        super(TwitterSignIn, self).__init__('twitter')
        self.service = OAuth1Service(
            name='twitter',
            consumer_key=self.consumer_id,
            consumer_secret=self.consumer_secret,
            request_token_url='https://api.twitter.com/oauth/request_token',
            authorize_url='https://api.twitter.com/oauth/authorize',
            access_token_url='https://api.twitter.com/oauth/access_token',
            base_url='https://api.twitter.com/1.1/'
        )

For Facebook, a provider that implements OAuth 2, the OAuth2Service class is used. The service object is initialized with the name of the service and several OAuth specific arguments. The client_id and client_secret arguments are the ones assigned to the application in Facebook's developer site. The authorize_url and access_token_url are URLs defined by Facebook for applications to connect to during the authentication process. Finally, the base_url sets the prefix URL for any Facebook API calls once the authentication is complete.

Twitter implements OAuth 1.0a, so class OAuth1Service is used instead. In OAuth 1.0a the id and secret codes are called consumer_key and consumer_secret, but are otherwise identical in functionality to the OAuth 2 counterparts. The OAuth 1 protocol requires providers to expose three URLs instead of two, there is an additional one called request_token_url. The name and base_url arguments are identical to the ones used in OAuth 2 services. I should note that Twitter offers two options for the authorize_url parameter. The URL shown above, https://api.twitter.com/oauth/authorize, is the most secure, as it will present the user with a screen in which they need to give permission to the app to access Twitter every time. Changing that URL to https://api.twitter.com/oauth/authenticate will make Twitter ask for permission just the first time, and then will silently allow access for as long as the user is logged in to Twitter.

Note that there is no standardization for the OAuth entry point URLs, OAuth providers define these as they like. To add a new OAuth provider you will need to obtain these URLs from the provider's documentation.

OAuth Authorization Phase

When the user clicks the "Login in with ..." link to initiate an OAuth authentication the following application route is invoked:

@app.route('/authorize/<provider>')
def oauth_authorize(provider):
    if not current_user.is_anonymous():
        return redirect(url_for('index'))
    oauth = OAuthSignIn.get_provider(provider)
    return oauth.authorize()

This route first ensures that the user is not logged in, and then simply obtains the OAuthSignIn subclass appropriate for the given provider, and invokes its authorize() method to initiate the process. The authorize() implementation for Facebook and Twitter is shown below:

class FacebookSignIn(OAuthSignIn):
    # ...
    def authorize(self):
        return redirect(self.service.get_authorize_url(
            scope='email',
            response_type='code',
            redirect_uri=self.get_callback_url())
        )

class TwitterSignIn(OAuthSignIn):
    # ...
    def authorize(self):
        request_token = self.service.get_request_token(
            params={'oauth_callback': self.get_callback_url()}
        )
        session['request_token'] = request_token
        return redirect(self.service.get_authorize_url(request_token[0]))

For OAuth 2 providers like Facebook the implementation simply issues a redirect to a URL generated by rauth's service object. The scope is provider specific, in this case I am asking that I want Facebook to provide the user's email. The response_type=code argument tells the OAuth provider that the application is a web application (there are other possible values for different authentication workflows). Finally, the redirect_uri argument is set to the application route that the provider needs to invoke after it completes the authentication.

OAuth 1.0a providers use a slightly more complicated process that involves obtaining a request token from the provider, which is a list of two items, the first of which is then used as an argument in the redirect. The entire request token is saved to the user session because it will be needed again in the callback.

OAuth Callback Phase

The OAuth provider redirects back to the application after the user authenticates and gives permission to share information. The route that handles this callback is shown below:

@app.route('/callback/<provider>')
def oauth_callback(provider):
    if not current_user.is_anonymous():
        return redirect(url_for('index'))
    oauth = OAuthSignIn.get_provider(provider)
    social_id, username, email = oauth.callback()
    if social_id is None:
        flash('Authentication failed.')
        return redirect(url_for('index'))
    user = User.query.filter_by(social_id=social_id).first()
    if not user:
        user = User(social_id=social_id, nickname=username, email=email)
        db.session.add(user)
        db.session.commit()
    login_user(user, True)
    return redirect(url_for('index'))

This route instantiates the OAuthSignIn provider class and invokes its callback() method. This method has the function to complete the authentication with the provider and obtain the user information. The return value is a tuple with three values, a unique id (called social_id to differentiate it from the id primary key), the user's nickname and the user's email. The id and the nickname are mandatory, but in this example application I made the email optional, since Twitter never shares that information with applications.

The user is searched in the database by the social_id field, and if not found, a new user is added to the database with the information obtained from the provider, effectively registering new users automatically. The user is then logged with the login_user() function of Flask-Login, and finally redirected to the home page.

The implementation of the callback() method for the Facebook and Twitter OAuth providers is shown below:

class FacebookSignIn(OAuthSignIn):
    # ...
    def callback(self):
        def decode_json(payload):
            return json.loads(payload.decode('utf-8'))

        if 'code' not in request.args:
            return None, None, None
        oauth_session = self.service.get_auth_session(
            data={'code': request.args['code'],
                  'grant_type': 'authorization_code',
                  'redirect_uri': self.get_callback_url()},
            decoder=decode_json
        )
        me = oauth_session.get('me').json()
        return (
            'facebook$' + me['id'],
            me.get('email').split('@')[0],  # Facebook does not provide
                                            # username, so the email's user
                                            # is used instead
            me.get('email')
        )

class TwitterSignIn(OAuthSignIn):
    # ...
    def callback(self):
        request_token = session.pop('request_token')
        if 'oauth_verifier' not in request.args:
            return None, None, None
        oauth_session = self.service.get_auth_session(
            request_token[0],
            request_token[1],
            data={'oauth_verifier': request.args['oauth_verifier']}
        )
        me = oauth_session.get('account/verify_credentials.json').json()
        social_id = 'twitter$' + str(me.get('id'))
        username = me.get('screen_name')
        return social_id, username, None   # Twitter does not provide email

In the callback() method the provider passes a verification token that the application can use to contact the provider's APIs. In the case of OAuth 2 this comes as a code argument, while for OAuth 1.0a it is oauth_verifier, both given in the query string. This code is used to obtain an oauth_session with the provider from the service object from rauth.

Note that in recent versions of the Facebook API, the session token is returned in JSON format. The default format that rauth expects for this token is to be provided in the query string of the request instead. For that reason, it is necessary to add a decoder argument that points to a function that decodes the JSON payload. In Python 2, it is sufficient to pass json.loads, but in Python 3 we need an additional step because the payload is returned as bytes, which the json parser does not understand. The conversion from bytes to string is done in the decode_json inner function.

The oauth_session object can be used to make API requests to the provider. Here it is used to request user information, which has to be done in a provider specific way. Facebook exposes a user id and an email, but does not give out usernames, so the username for the application is created from the left portion of the email address. Twitter provides the id and the username, but does not share emails, so the email is returned as None. The data obtained from the provider is finally returned as a three element tuple to the view function.

Note how in both cases the id value from the provider is prepended with "facebook$" or "twitter$" before it is returned, to make it unique across all providers. Since this is what the application will store as social_id in the database, it is necessary to do this to ensure that two providers that assign the same id to two different users do not collide in the application's database.

Conclusion

As I mentioned above, the example application allows any user to register and login with either a Facebook or a Twitter account. The application demonstrates how to register and login users without them having to enter any information, all they need to do is to login with the provider and authorize the sharing of information.

If you want to try this example, you need to follow some preparatory steps:

  • Clone or download the project's repository: https://github.com/miguelgrinberg/flask-oauth-example
  • Create a virtual environment and install the packages in the requirements.txt file (you can use Python 2.7 or 3.4).
  • Register "apps" with Facebook and Twitter, as described above.
  • Edit app.py with the id and secret codes of your Facebook and Twitter apps.

After you complete these instructions, you can run the application with python app.py, and then visit http://localhost:5000 in your browser.

I hope this article is useful in demystifying OAuth a little bit. If you have any questions feel free to write them below.

Miguel

Become a Patron!

Hello, and thank you for visiting my blog! If you enjoyed this article, please consider supporting my work on this blog on Patreon!

173 comments
  • #126 Wisarut said

    Hi Miguel, I have applied your OAUTH authentication with flask to enable user to log into web app by Google Plus but I got "ValueError: View function did not return a response" during the authorization stage.

    It seems to me that something have gone wrong in my initialization and authorization code within class GoogleSignIn:

    here is the initialization and authorization function within google and related functions
    class GoogleSignIn(OAuthSignIn):
    def init(self):
    super(GoogleSignIn, self).init('google')
    self.service = OAuth2Service(
    name='google',
    client_id=self.consumer_id,
    client_secret=self.consumer_secret,
    authorize_url='https://accounts.google.com/o/oauth2/v2/auth',
    access_token_url='https://www.googleapis.com/oauth2/v4/token',
    base_url='https://www.googleapis.com/oauth2/v3/userinfo'
    )

    def authorize(self):
        return redirect(self.service.get_authorize_url(
            scope='email',
            response_type='code',
            state=self.state,
            redirect_uri=self.get_callback_url()))
    

    //-----------------------------------------------------
    class OAuthSignIn(object):
    providers = None

    def __init__(self, provider_name):
        self.provider_name = provider_name
        credentials = current_app.config['OAUTH_CREDENTIALS'][provider_name]
        self.consumer_id = credentials['id']
        self.consumer_secret = credentials['secret']
    
    def authorize(self):
        pass
    
    def callback(self):
        pass
    def validate_oauth2callback(self):
        if 'code' not in request.args: #dump request if problem
        abort(500, 'oauth2 callback: code not in request.args: \n' + str(request.__dict__))
        if request.args.get('state') != session.get('state'):
        abort(500, 'oauth2 callback: state does not match: \n' + str(request.__dict__))
    def get_callback_url(self):
        return url_for('oauth_callback', provider=self.provider_name,
                       _external=True)
    
    @classmethod
    def get_provider(self, provider_name):
        if self.providers is None:
            self.providers = {}
            for provider_class in self.__subclasses__():
                try:
            provider = provider_class()
                except KeyError:
            pass # unsupport provider
        else:
            self.providers[provider.provider_name] = provider
        return self.providers[provider_name]
    
  • #127 Miguel Grinberg said

    @Wisarut: Can't really tell from looking at the portion of the code you shared, which does not include any view functions. Did you look at the view function in question? Not returning a response should be a pretty clear mistake, that's a view function that does not end with a return statement.

  • #128 Viktor Almén said

    Hi! I would like to make the login functionality open to invited users only. I could just remove the automatic user creation, but then I would have to know the user details and create the user in the database before the user's first login attempt. I would prefer to keep the automatic user creation, but that it would only work for users who have received an invitation, for example via email.
    Do you have any suggestions for how to solve this?

  • #129 Miguel Grinberg said

    @Viktor: You have an interesting problem. What I would do, is use a JWT as an invitation token. The invitation link will include this JWT. If the server verifies the signature in the JWT, then you know the invitation is valid. Hope this helps!

  • #130 Ryan Paul said

    Hi...Miguel this was really interesting thank you so much however when I tried to run it I receive an error like this "Can't Load URL: The domain of this URL isn't included in the app's domains. To be able to load this URL, add all domains and subdomains of your app to the App Domains field in your app settings." i researched but still it won't work. Can you help me with this.

  • #131 Miguel Grinberg said

    @Ryan: this is explained in the "Registration with OAuth Providers" section. You have to register the callback URL, OAuth providers will not blindly invoke any URL that you give them.

  • #132 Mike Tung said

    Hi Miguel,

    Great article! I'm still new to the OAuth2 and have successfully implemented the 3-legged flow, my question is once I have the auth token and have gotten the user account, what do you suggest in terms of authorization?
    Specifically I'm building out a REST api and trying to maintain statelessness with OAuth, but I'm hitting a bit of a snag with figuring out how to handle the user from that point on.

  • #133 Miguel Grinberg said

    @Mike: One possible approach is to store the OAuth2 token in your database (in case you need to talk to the provider service) and generate a separate token of your own to give to your client. The token can be a JWT, or can also be a randomly generated token that you store in your database. Hope this helps.

  • #134 Wisarut Bholsithi said

    Hi...Miguel, I also got into the problem of Facebook Connect error code 191 which states that:

    "Can't Load URL: The domain of this URL isn't included in the app's domains. To be able to load this URL, add all domains and subdomains of your app to the App Domains field in your app settings."

    You have said that I have to register the callback URL, but how to do that? I have already added the callback URL ( http://zsize.fwd.wf/callback/facebook) into the Valid OAuth redirect URIs page but it does not solve the problem of "Can't Load URL: The domain of this URL isn't included in the app's domains" problem though.

    I use Facebook API version 2.10 though.

  • #135 Miguel Grinberg said

    @Wisarut: Not sure what else can be. The only case I've seen for this error is when the callback domain registered with the app on the facebook dev site does not match what you set in your own application.

  • #136 Jeremy Epstein said

    @Victor (re: comment 128): I came up with a hacky solution to "invite-only oauth login" a long time ago, see http://greenash.net.au/thoughts/2011/11/django-facebook-user-integration-with-whitelisting/ - was with Django not Flask, and Facebook's API has no doubt changed a bit in the years since. I don't particularly recommend emulating what I did, I wouldn't call it exemplary, but it might give you some ideas.

  • #137 Louis said

    hello thank for your article, i start with python , flask and inglish. i clone your directory and i try to use it but when i click on facebook link i get this error
    {
    "error": {
    "message": "Impossibile caricare l'URL: Il dominio di questo URL non \u00e8 incluso nei domini dell'app. Per poter caricare questo URL, aggiungi tutti i domini e i sottodomini della tua app al campo Domini app nelle tue impostazioni app.",
    "type": "OAuthException",
    "code": 191,
    "fbtrace_id": "DckkBl7vP8M"
    }
    }

    is in italian and say "is impossible to load this url : the domain of this URL \ \u00e8 isn't present on domain list of the app. you must to add this add this doman on your app list domain"

  • #138 Miguel Grinberg said

    @Louis: the error message is actually correct. Review the "Registration with OAuth Providers" section for information on how to register your domain with the OAuth provider.

  • #139 Wisarut Bholsithi said

    Now, it seems to me that after FaceBook has enabled Strict Mode for Redirect URIs while preventing any disable, I was unable to make a Facebook Login as I used be.

    When I added "http://127.0.0.1.nip.io/callback/facebook" into "Valid OAuth Redirect URIs" as the way to deal with the error "Can't Load URL: The domain of this URL isn't included in the app's domains...", I have found that it has caused "HTTP Error 404.0 - Not Found"

    BTW, I used https://forwardhq.com to create tunnel which turning 127.0.0.1.nip.io:8000 into zsize.fwd.wf though.

  • #140 Miguel Grinberg said

    @Wisarut: Have you tried using your localhost based address as the redirect? Not sure if FB allows redirect services.

  • #141 Avinash Bhosale said

    Hi Miguel, Your articles are the best one resource for learning the flask.
    I would like to user the Oauth 2.0 for Rest-API's for Flask Framework.
    I am not getting how to do this. Please suggest me.

  • #142 Miguel Grinberg said

    @Avinash: Try the Flask-OAuthlib package: https://github.com/lepture/flask-oauthlib

  • #143 Avinash said

    Hii Miguel , your posts regarding the flask are very useful. I want to user Oauth 2 for flask Rest api. I want only the package which can act as Oauth Server and depending on the Authorization he will give Access token, refresh token and other things which will be useful for developing and securing the Rest api.

  • #144 Miguel Grinberg said

    @Avinash: what you are asking about is not the topic of this article, which is about using third party OAuth servers. You may want to look into OAuthLib.

  • #145 Wisarut said

    Hi Miguel, Now I got a trouble on the using FaceBook Login since it keeps showing that

    "OAuthException 191 - Can't Load URL: The domain of this URL isn't included in the app's domains"

    the redirect_uri shown in https://graph.facebook.com/oauth/authorize is "http://zsize.openservice.in.th/callback/facebook" instead of "https://zsize.openservice.in.th/callback/facebook"

    Despite of the fact that I have put https://zsize.openservice.in.th/callback/facebook as Valid OAuth Redirect URIs.

    When I change from http://zsize.openservice.in.th/callback/facebook to https://zsize.openservice.in.th/callback/facebook, I got Error 500: Internal Server Error.

    How can I deal with this kind of trouble? Please Help me.

  • #146 Miguel Grinberg said

    @Wisarut: I believe Facebook and many other OAuth providers require the callback endpoint to be https. The only exception is when you use a localhost endpoint for development. For the 500 error you need to look at the logs in your flask application, there should be a stack trace there that matches this error.

  • #147 Wisarut said

    @Miguel Grinberg, It seems to me that I had better use the latest update of the FaceBook API for Facebook Login to deal with this problem.

  • #148 Miguel Grinberg said

    @Wisarut: did you check your application logs for the error as I suggested? Without knowing what the error is about I cannot comment.

  • #149 Wisarut said

    Hi Miguel,

    After changing the URIs in the Valid OAuth Redirect URIs to "https://zsize.openservice.in.th/callback/facebook" and "https://zsize.openservice.in.th/callback/facebook/" I have found that the redirect_uri still using http (http://zsize.openservice.in.th/) instead of https (https://zsize.openservice.in.th/) and this case of redirect_uri still using http instead of https

    [code]{
    "error": {
    "message": "Can't load URL: The domain of this URL isn't included in the app's domains. To be able to load this URL, add all domains and sub-domains of your app to the App Domains field in your app settings.",
    "type": "OAuthException",
    "code": 191,
    "fbtrace_id": "E+6n8W/dTnA"
    }
    }[/code]

    I have already set the Basic section of Facebook API to https://zsize.openservice.in.th/ and App Domain to zsize.openservice.in.th.

    How can I deal with this kind of error? I even tried to debug to find the actual result from "self.get_callback_url()" in function "callback(self)" within oauth2.py to track down the result from get_callback_url but I still unable to do so.

    I use django API as the intermediate container to handle the login surge.

    If you could give me a clue on how to obtain the result from get_callback_url as well as the way to deal with this "Can't load URL: The domain of this URL isn't included in the app's domains.", I would be appreciated

  • #150 Miguel Grinberg said

    @Wisarut: use the network tab of your browser's console to debug this. I can't really help, if the authentication is being done with the http URL then you must have that still configured and need to change it to https.

Leave a Comment