# Quick start This tutorial builds a small Flask app with GitHub login, a callback, a profile route that calls GitHub, and logout. ## Before you start 1. [Install the package](installation.md). 2. [Create a GitHub OAuth App](installation.md#register-a-github-oauth-app). 3. Set its callback URL to `http://localhost:5000/callback`. For local development, provide the OAuth credentials and a Flask secret in your shell: ```console export SECRET_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')" export GITHUB_CLIENT_ID="your-oauth-app-client-id" export GITHUB_CLIENT_SECRET="your-oauth-app-client-secret" ``` The generated `SECRET_KEY` is for local development. Keep it stable while you use the app; changing it invalidates Flask's signed session cookies. For deployed applications, supply secrets through your platform's secret manager or environment configuration. ## Create `app.py` ```python import os import flask import flask_githubkit app = flask.Flask(__name__) app.config.from_mapping( SECRET_KEY=os.environ["SECRET_KEY"], GITHUB_CLIENT_ID=os.environ["GITHUB_CLIENT_ID"], GITHUB_CLIENT_SECRET=os.environ["GITHUB_CLIENT_SECRET"], GITHUB_SCOPE="read:user", ) github = flask_githubkit.GitHub(app) @app.route("/") def index(): return ( 'Sign in with GitHub ' 'View profile ' 'Sign out' ) @app.route("/login") @github.login def login(): """The decorator redirects to GitHub; this body is not called.""" @app.route("/callback") @github.callback def callback(access_token): if access_token is None: return "GitHub authorization was denied.", 401 return flask.redirect(flask.url_for("profile")) @app.route("/profile") def profile(): client = github.client() if client is None: return flask.redirect(flask.url_for("login")) user = client.rest.users.get_authenticated().parsed_data return flask.jsonify(login=user.login) @app.route("/logout") def logout(): github.logout() return flask.redirect(flask.url_for("index")) ``` ## Run the app From the directory containing `app.py`, start Flask: ```console flask --app app run ``` Open `http://localhost:5000/` and choose **Sign in with GitHub**. Completing the flow requires a working OAuth App and network access to GitHub. ```{note} On recent macOS versions, AirPlay Receiver can occupy port 5000. If Flask cannot bind to it, disable AirPlay Receiver or run on another port, and use the same port in the OAuth App's callback URL. ``` ## What happens during login 1. `@github.login` redirects the browser to GitHub and stores a random `state` value in the Flask session. 2. GitHub sends the browser back to the `@github.callback` route with an authorization code and the `state`. 3. `@github.callback` checks and consumes the `state`. If it is valid, the extension exchanges the code for a token, saves the token in the session, and calls `callback(access_token)`. 4. The profile route calls `github.client()`. The extension loads the session token and returns a GitHubKit client for the request. 5. GitHubKit refreshes an expired access token when the client is used. flask-githubkit saves the updated token values to the session after the request. The profile route does not need the `access_token` argument from the callback. The extension persists the token in the session so later routes can use `github.client()`. Prefer GitHubKit API methods over handling the raw token. ## Denied and invalid callbacks If the user denies authorization, the decorated callback view is called with `None`, allowing your app to show a message or redirect. A callback with missing or invalid `state` is rejected with HTTP 400 before the view runs. The one-time state value is consumed on the first callback attempt, so a replay is rejected. For application factories and Blueprints, see [complete examples](examples.md).