Skip to content

Commit

Permalink
add google_auth example (#161)
Browse files Browse the repository at this point in the history
  • Loading branch information
masenf authored Oct 26, 2023
1 parent 551425f commit 93aa38b
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 0 deletions.
23 changes: 23 additions & 0 deletions google_auth/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Google Auth

Built using https://github.com/MomenSherif/react-oauth, many more options are
available than what is wrapped here.

## Usage

* **Always use TLS in production!**

* Get a client ID from https://console.developers.google.com/apis/credentials
* Set the environment variable `GOOGLE_CLIENT_ID` to the client ID.
* Client secret is not required.

## Demo

### Obtaining Client ID

https://github.com/reflex-dev/reflex-examples/assets/1524005/af2499a6-0bda-4d60-b52b-4f51b7322fd5

### Logging In

https://github.com/reflex-dev/reflex-examples/assets/1524005/b0c7145b-6c19-4072-bc9d-ae8927c8988f

Binary file added google_auth/assets/favicon.ico
Binary file not shown.
Empty file.
111 changes: 111 additions & 0 deletions google_auth/google_auth/google_auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import functools
import json
import os
import time

from google.auth.transport import requests
from google.oauth2.id_token import verify_oauth2_token

import reflex as rx

from .react_oauth_google import GoogleOAuthProvider, GoogleLogin

CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", "")


class State(rx.State):
id_token_json: str = rx.LocalStorage()

def on_success(self, id_token: dict):
self.id_token_json = json.dumps(id_token)

@rx.cached_var
def tokeninfo(self) -> dict[str, str]:
try:
return verify_oauth2_token(
json.loads(self.id_token_json)["credential"],
requests.Request(),
CLIENT_ID,
)
except Exception as exc:
if self.id_token_json:
print(f"Error verifying token: {exc}")
return {}

def logout(self):
self.id_token_json = ""

@rx.var
def token_is_valid(self) -> bool:
try:
return bool(
self.tokeninfo
and int(self.tokeninfo.get("exp", 0)) > time.time()
)
except Exception:
return False

@rx.cached_var
def protected_content(self) -> str:
if self.token_is_valid:
return f"This content can only be viewed by a logged in User. Nice to see you {self.tokeninfo['name']}"
return "Not logged in."


def user_info(tokeninfo: dict) -> rx.Component:
return rx.hstack(
rx.avatar(
name=tokeninfo["name"],
src=tokeninfo["picture"],
size="lg",
),
rx.vstack(
rx.heading(tokeninfo["name"], size="md"),
rx.text(tokeninfo["email"]),
align_items="flex-start",
),
rx.button("Logout", on_click=State.logout),
padding="10px",
)


def login() -> rx.Component:
return rx.vstack(
GoogleLogin.create(on_success=State.on_success),
)


def require_google_login(page) -> rx.Component:
@functools.wraps(page)
def _auth_wrapper() -> rx.Component:
return GoogleOAuthProvider.create(
rx.cond(
State.is_hydrated,
rx.cond(State.token_is_valid, page(), login()),
rx.spinner(),
),
client_id=CLIENT_ID,
)
return _auth_wrapper


def index():
return rx.vstack(
rx.heading("Google OAuth", size="lg"),
rx.link("Protected Page", href="/protected"),
)


@rx.page(route="/protected")
@require_google_login
def protected() -> rx.Component:
return rx.vstack(
user_info(State.tokeninfo),
rx.text(State.protected_content),
rx.link("Home", href="/"),
)


app = rx.App()
app.add_page(index)
app.compile()
16 changes: 16 additions & 0 deletions google_auth/google_auth/react_oauth_google.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import reflex as rx


class GoogleOAuthProvider(rx.Component):
library = "@react-oauth/google"
tag = "GoogleOAuthProvider"

client_id: rx.Var[str]


class GoogleLogin(rx.Component):
library = "@react-oauth/google"
tag = "GoogleLogin"

def get_event_triggers(self):
return {"on_success": lambda data: [data]}
2 changes: 2 additions & 0 deletions google_auth/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
google-auth[requests]
reflex>=0.2.9
5 changes: 5 additions & 0 deletions google_auth/rxconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import reflex as rx

config = rx.Config(
app_name="google_auth",
)

0 comments on commit 93aa38b

Please sign in to comment.