{"id":17686322,"url":"https://github.com/shihanng/flask-login-example","last_synced_at":"2025-09-11T16:49:13.083Z","repository":{"id":84061029,"uuid":"139370114","full_name":"shihanng/flask-login-example","owner":"shihanng","description":" A very simple Flask application that demonstrates how to integrate OpenID connect into user session management.","archived":false,"fork":false,"pushed_at":"2018-07-05T23:39:19.000Z","size":25,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-13T00:09:55.097Z","etag":null,"topics":["flask","flask-login","google-oauth2","openid-connect","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shihanng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-07-01T23:32:59.000Z","updated_at":"2023-03-11T10:58:52.000Z","dependencies_parsed_at":null,"dependency_job_id":"3ca783de-c312-4ccc-ae67-74a2ae17f075","html_url":"https://github.com/shihanng/flask-login-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/shihanng/flask-login-example","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shihanng%2Fflask-login-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shihanng%2Fflask-login-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shihanng%2Fflask-login-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shihanng%2Fflask-login-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shihanng","download_url":"https://codeload.github.com/shihanng/flask-login-example/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shihanng%2Fflask-login-example/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274672869,"owners_count":25328550,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-11T02:00:13.660Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flask","flask-login","google-oauth2","openid-connect","python3"],"created_at":"2024-10-24T10:44:32.274Z","updated_at":"2025-09-11T16:49:13.045Z","avatar_url":"https://github.com/shihanng.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# simple-login\n\nThe aim of this document is to provide a simple guide on\nhow to create a web application that requires user to login\nvia [OpenID connect](http://openid.net/connect/) to view a specific page.\nThe web application is built with [Python 3](https://www.python.org/)\nand the [Flask](http://flask.pocoo.org/).\nThe user login session is managed with the help of\n[Flask-Login](http://flask-login.readthedocs.io/en/latest/) and\n[Flask-Session](https://pythonhosted.org/Flask-Session/).\nSee [setup.py](./setup.py) for the dependencies.\n\n## Start Development Server\n\nLet's make sure that everything is running as promised.\n\n##### 1. Create a virtual environment and install the dependencies.\n```sh\npython3 -mvenv env\npip install --editable .\n```\n\n##### 2. Setup the following environment variables. `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` can be obtained from Google's Credentials page, see [section \"Obtain OAuth 2.0 credentials\" in this guide](https://developers.google.com/identity/protocols/OpenIDConnect#getcredentials).\n\n```\nexport FLASK_ENV=development\nexport GOOGLE_CLIENT_ID=\nexport GOOGLE_CLIENT_SECRET=\n```\n\n##### 3-a. Using the `flask run` command\n```\nexport FLASK_APP=src/simple_login/app.py\nflask run\n```\n\n##### 3-b. Using the `setup.py`'s `entry_points`\n```\napp\n```\n\n##### 4. Visit [localhost:5000](http://localhost:5000) to confirm the app is running.\nProcess with the \"login from here\" and complete the login.\nThen visit [localhost:5000/secret](http://localhost:5000/secret)\nWe should be able to see\n\u003e Only logged in user can see this.\n\n## The Essentials\n\nAs the `entry_points` in [setup.py](./setup.py) indicates, the application\nstarts from [./src/simple_login/app.py](./src/simple_login/app.py).\n\n### Configurations\n\nThe configuations of the application are stored in the environment.\nThis is one of the practices recommended by\n[the Twelve-Factor App](https://12factor.net/config).\n\n```python\nGOOGLE_CLIENT_ID = os.environ.get(\"GOOGLE_CLIENT_ID\", default=\"\")\n```\n\nTo load the configurations into our application, we use,\n```python\napp.config.from_object(__name__)\n```\nwhich loads only the uppercase attributes of the module/class.\nTo access the configurations within the application, we do\n```python\ncurrent_app.config[\"GOOGLE_CLIENT_ID\"]\n```\nCheck out the official documentation to learn more about\n[configuration handling](http://flask.pocoo.org/docs/1.0/config/).\n\n### Sessions\n\nThe default [Flask's session](http://flask.pocoo.org/docs/1.0/api/#flask.session)\nstores the values in cookies not on the server side by default.\nThis means that we should not store anything sensitive in the default cookie.\nFor server side session, we can use the extension\n[Flask-Session](https://pythonhosted.org/Flask-Session/)\nHere in [our example](./src/simple_login/app.py) we setup the application\nto store the session in our local filesystem.\n```python\nSESSION_TYPE = 'filesystem'\n\nSession(app)\n```\nThen use the [flask.session](http://flask.pocoo.org/docs/api/#flask.session)\nobject which works like an ordinary dict to access the values:\n```python\nsession['state'] = state  # Store\nv = session['state']      # Retrieve\n```\n\n### Managing Logins\n\nWe can manage user login with the\n[Flask-Login](http://flask-login.readthedocs.io/en/latest/)\nlibrary which store active user's ID in the session that we've setup above.\n```python\nlogin_manager = LoginManager()\nlogin_manager.init_app(app)\n```\nIn addition to the setup above, we also need to provide a our user class.\n```python\nclass User(object):\n```\nand a [`user_loader`](http://flask-login.readthedocs.io/en/latest/#how-it-works)\ncallback which will return either the user of a given `user_id` from the database,\nor None if the Id is invalid:\n\n```python\n@login_manager.user_loader\ndef load_user(user_id) -\u003e Optional[User]:\n    app.logger.debug('looking for user %s', user_id)\n    u = users.get(user_id, None)\n    app.logger.debug('id is %s', id)\n    if not id:\n        return None\n    return u\n```\n\nFor the sake of simplicity, our database is just a simple dict\nwithin the application.\n\n```python\nusers: Dict[str, User] = {}\n```\n\n## Walk-through\n\n1. When a user visits [localhost:5000](http://localhost:5000),\n   Flask will render the index page using the\n   [templates/index.html](./templates/index.html)\n   that lead the user to [localhost:5000/login](http://localhost:5000/login).\n\n2. The login process starts with creating an anti-forgery state token,\n   and nonce for replay protection.\n   Both values are stored in the server-side session and the client (browser)\n   holds the session ID in cookies.\n\n3. Then an authentication request is sent to Google and the user will be\n   redirect to the Google consent page.\n\n4. The response after the consent is given will be received by\n   the `/callback` endpoint. At this point we should verify that the value of\n   the `state` from Google matches the one we've stored in the session.\n\n5. Using the `code` parameter from the response, a POST request is made to\n   Google for exchanging the access token and ID token.\n\n6. The `id_token` (a JWT) field should be found in the successful response\n   to the POST request. After base64 decode the `id_token` we should verify\n   the `nonce` field and remove the `nonce` from our session.\n   Then we create the our application User based on the\n   id obtained from the `sub` field, store it in our `users` DB,\n   and login the user with Flask-Login: `login_user(u)`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshihanng%2Fflask-login-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshihanng%2Fflask-login-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshihanng%2Fflask-login-example/lists"}