Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Injected auth models #1583

Merged
merged 66 commits into from
Jan 3, 2024
Merged
Changes from 1 commit
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
87a24b1
WIP: Auth entity
infomiho Nov 15, 2023
7749dec
Merge branch 'main' into auth-model-experiment
infomiho Nov 15, 2023
a7e3c14
Username and password working
infomiho Nov 15, 2023
bf77d11
Add support for email auth
infomiho Nov 15, 2023
238c3a8
Add support for Social auth
infomiho Nov 15, 2023
627ecf9
Add tasks to User
infomiho Nov 16, 2023
4259689
Update authentication providers and entities
infomiho Nov 24, 2023
20d4fd4
Email authentication. Test adding signup fields
infomiho Nov 24, 2023
33eb3aa
Migration with seed scripts
infomiho Nov 24, 2023
993e39d
Migrate Todo app
infomiho Nov 24, 2023
cf38191
Clenaup
infomiho Nov 27, 2023
9dfbd6c
Remove example app
infomiho Nov 27, 2023
4d0e3e4
Cleanup
infomiho Nov 27, 2023
a768c36
Updates tests
infomiho Nov 27, 2023
83ad555
Cleanup
infomiho Nov 27, 2023
8693c69
Fixes tests
infomiho Nov 28, 2023
43fb9f7
Merge branch 'main' into auth-model-experiment
infomiho Dec 12, 2023
e6f6a17
Use JSON based auth model
infomiho Dec 12, 2023
2714731
Refactor provider data serialization
infomiho Dec 12, 2023
872bca1
Updates typing of provider data
infomiho Dec 13, 2023
fd87def
Remove Prisma middleware. Fixes types
infomiho Dec 13, 2023
3ae0468
Cleanup
infomiho Dec 13, 2023
b5e0c05
Fixes double password hashing issue
infomiho Dec 13, 2023
315962f
Fixes headless test
infomiho Dec 13, 2023
95bda0a
Update e2e tests
infomiho Dec 13, 2023
efc2291
Cleanup
infomiho Dec 13, 2023
7fa0fe1
Merge branch 'main' into auth-model-experiment
infomiho Dec 14, 2023
21b0e77
Updates utils.ts. Updates websocket example app
infomiho Dec 14, 2023
f94f7fd
Update e2e tests
infomiho Dec 14, 2023
0a1d965
Update examples apps. Update server utils.ts
infomiho Dec 14, 2023
52f0881
PR comments
infomiho Dec 18, 2023
f982e6d
Updates e2e tests
infomiho Dec 18, 2023
48484c1
Add user ID helpers
infomiho Dec 18, 2023
6ba6a21
Fixes e2e tests
infomiho Dec 18, 2023
cf19e38
Improve naming and types
infomiho Dec 19, 2023
c5aee00
Updates e2e tests
infomiho Dec 19, 2023
a3cb241
Update examples/waspello/src/client/Navbar.jsx
infomiho Dec 19, 2023
b0b1a8b
PR comments
infomiho Dec 21, 2023
ce1c89b
PR comments
infomiho Dec 21, 2023
c3e46dc
Minor fixes. Rename local provider to username
infomiho Dec 22, 2023
c58ed9c
Updates e2e tests
infomiho Dec 22, 2023
2429673
Fixes frontend unit tests
infomiho Dec 22, 2023
d71d0f7
PR comments
infomiho Dec 22, 2023
8d27abb
Update e2e tests
infomiho Dec 22, 2023
d9690bb
Improve username handling in examples. Add getFirstProviderUserId
infomiho Dec 22, 2023
226e38b
Update e2e tests
infomiho Dec 22, 2023
9303dbc
Update seed script path
infomiho Dec 22, 2023
7ea4792
Add comment above PossibleProviderData
infomiho Dec 22, 2023
887ce20
Use UTC date for auth related timings
infomiho Dec 22, 2023
215bb86
Updates e2e tests
infomiho Dec 22, 2023
227a2f8
unverfiied email signup flow. foregin constraint error
infomiho Dec 23, 2023
1c53057
e2e tests
infomiho Dec 23, 2023
5daf665
Use token in email verification and password reset
infomiho Dec 23, 2023
4d1a863
e2e tests
infomiho Dec 23, 2023
dba9d28
Fix user creation and deletion errors
infomiho Dec 27, 2023
c313736
e2e tests
infomiho Dec 27, 2023
acf5d1f
PR comments
infomiho Dec 29, 2023
49966c0
PR comments
infomiho Jan 2, 2024
7c1b66e
Update e2e tests
infomiho Jan 2, 2024
04a9ee1
Extract the oauth handler into a separate function
infomiho Jan 2, 2024
d84dcc9
e2e tests
infomiho Jan 2, 2024
d4339a4
Update waspc/data/Generator/templates/server/src/auth/providers/email…
infomiho Jan 3, 2024
5077add
Apply suggestions from code review
infomiho Jan 3, 2024
9e4d7bb
Merge branch 'main' into auth-model-experiment
infomiho Jan 3, 2024
993eeac
PR comments
infomiho Jan 3, 2024
9b1185d
e2e tests
infomiho Jan 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add user ID helpers
infomiho committed Dec 18, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 48484c17b573d0df031a6b549e9ee03d39a9ac32
7 changes: 1 addition & 6 deletions examples/thoughts/src/client/TopNavbar.jsx
Original file line number Diff line number Diff line change
@@ -4,12 +4,7 @@ import logout from "@wasp/auth/logout";

import "./TopNavbar.css";

function getUsername(user) {
const usernameIdentity = user.auth.identities.find(
(identity) => identity.providerName === "username"
);
return usernameIdentity ? usernameIdentity.providerUserId : null;
}
import { getUsername } from "@wasp/auth/user";

const TopNavbar = ({ user }) => {
const username = getUsername(user);
7 changes: 1 addition & 6 deletions examples/todo-typescript/src/client/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -11,12 +11,7 @@ import updateTask from "@wasp/actions/updateTask";
import deleteTasks from "@wasp/actions/deleteTasks";
import type { Task } from "@wasp/entities";
import type { User } from "@wasp/auth/types";

function getUsername(user: User) {
return user.auth?.identities.find(
(identity) => identity.providerName === "username"
)?.providerUserId;
}
import { getUsername } from "@wasp/auth/user";

export const MainPage = ({ user }: { user: User }) => {
const { data: tasks, isLoading, error } = useQuery(getTasks);
14 changes: 12 additions & 2 deletions examples/waspello/src/client/Navbar.jsx
Original file line number Diff line number Diff line change
@@ -5,8 +5,18 @@ import logout from "@wasp/auth/logout";
import logo from "./waspello-logo-navbar.svg";
import "./Navbar.css";

import { findUserIdentity, getUsername } from "@wasp/auth/user";

const Navbar = ({ user }) => {
const identifier = user.auth?.identities[0]?.providerUserId;
// We have to ways of authenticating users, so
infomiho marked this conversation as resolved.
Show resolved Hide resolved
// we have to check which one is used.
const googleIdentity = findUserIdentity(user, "google");
const usernameIdentity = findUserIdentity(user, "username");

const username = usernameIdentity
? getUsername(user)
: `Google user ${googleIdentity.providerUserId}`;
Martinsos marked this conversation as resolved.
Show resolved Hide resolved

return (
<div className="navbar">
<div className="navbar-item">
@@ -17,7 +27,7 @@ const Navbar = ({ user }) => {

<div className="navbar-item">
<span>
{identifier}
{username}
&nbsp;|&nbsp;
<button className="logout-btn" onClick={logout}>
{" "}
11 changes: 5 additions & 6 deletions examples/websockets-realtime-voting/src/client/Layout.jsx
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import "./Main.css";
import { Flowbite, Dropdown, Navbar, Avatar } from "flowbite-react";
import Logo from "./logo.png";
import useAuth from "@wasp/auth/useAuth";
import { getUsername } from "@wasp/auth/user";
import logout from "@wasp/auth/logout";

const customTheme = {
@@ -17,8 +18,6 @@ const customTheme = {
export const Layout = ({ children }) => {
const { data: user } = useAuth();

const identity = user?.auth?.identities[0];

return (
<Flowbite theme={{ theme: customTheme }}>
<div className="p-8">
@@ -36,15 +35,15 @@ export const Layout = ({ children }) => {
label={
<Avatar
alt="User settings"
img={`https://xsgames.co/randomusers/avatar.php?g=female&username=${identity?.providerUserId}`}
img={`https://xsgames.co/randomusers/avatar.php?g=female&username=${getUsername(
user
)}`}
rounded
/>
}
>
<Dropdown.Header>
<span className="block text-sm">
{identity?.providerUserId}
</span>
<span className="block text-sm">{getUsername(user)}</span>
</Dropdown.Header>
<Dropdown.Item>Dashboard</Dropdown.Item>
<Dropdown.Item>Settings</Dropdown.Item>
4 changes: 2 additions & 2 deletions examples/websockets-realtime-voting/src/server/ws-server.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { WebSocketDefinition } from "@wasp/webSocket";
import { getUsername } from "@wasp/auth/user.js";

type PollState = {
question: string;
@@ -53,8 +54,7 @@ export const webSocketFn: WebSocketDefinition<
return;
}

const connectionUsername =
socket.data.user.auth?.identities[0].providerUserId;
const connectionUsername = getUsername(socket.data.user);

console.log("Socket connected: ", connectionUsername);
socket.on("askForStateUpdate", () => {
15 changes: 15 additions & 0 deletions waspc/data/Generator/templates/react-app/src/auth/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { User } from './types'

export function getEmail(user: User) {
return findUserIdentity(user, "email")?.providerUserId ?? null;
}

export function getUsername(user: User) {
return findUserIdentity(user, "username")?.providerUserId ?? null;
infomiho marked this conversation as resolved.
Show resolved Hide resolved
}

export function findUserIdentity(user: User, providerName: string) {
Martinsos marked this conversation as resolved.
Show resolved Hide resolved
return user.auth.identities.find(
(identity) => identity.providerName === providerName
);
}
15 changes: 15 additions & 0 deletions waspc/data/Generator/templates/server/src/auth/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import type { SanitizedUser as User } from '../_types/index'
Martinsos marked this conversation as resolved.
Show resolved Hide resolved

export function getEmail(user: User) {
return findUserIdentity(user, "email")?.providerUserId ?? null;
}

export function getUsername(user: User) {
return findUserIdentity(user, "username")?.providerUserId ?? null;
}

export function findUserIdentity(user: User, providerName: string) {
return user.auth.identities.find(
(identity) => identity.providerName === providerName
);
}
12 changes: 3 additions & 9 deletions waspc/examples/crud-testing/src/client/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -3,9 +3,10 @@ import './Main.css'
import React, { useState } from 'react'
import { Link, routes } from '@wasp/router'
import logout from '@wasp/auth/logout'
import { getUsername } from '@wasp/auth/user'

import { tasks as tasksCrud } from '@wasp/crud/tasks'
import { User, AuthIdentity } from '@wasp/entities'
import { User } from '@wasp/entities'

const MainPage = ({ user }: { user: User }) => {
const { data: tasks, isLoading } = tasksCrud.getAll.useQuery()
@@ -62,13 +63,6 @@ const MainPage = ({ user }: { user: User }) => {
}
}

type User = NonNullable<typeof tasks>[number]['user']

function findUsername(user: User) {
return user.auth?.identities.find((i) => i.providerName === 'username')
?.providerUserId
}

return (
<div className="container">
<main>
@@ -105,7 +99,7 @@ const MainPage = ({ user }: { user: User }) => {
{routes.DetailRoute.build({
params: { id: task.id, something: 'else' },
})}{' '}
by {findUsername(task.user)}
by {getUsername(task.user)}
</Link>
</div>
<button onClick={() => handleTaskDelete(task)}>Delete</button>
5 changes: 2 additions & 3 deletions waspc/examples/todoApp/src/client/App.tsx
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import getDate from '@wasp/queries/getDate'
import { useSocket } from '@wasp/webSocket'

import './Main.css'
import { getName } from './user'

export function App({ children }: any) {
const { data: user } = useAuth()
@@ -15,8 +16,6 @@ export function App({ children }: any) {

const connectionIcon = isConnected ? '🟢' : '🔴'

const identity = user?.auth?.identities[0]

return (
<div className="app border-spacing-2 p-4">
<header className="flex justify-between">
@@ -29,7 +28,7 @@ export function App({ children }: any) {
{user && (
<div className="flex gap-3 items-center">
<div>
Hello, <Link to="/profile">{identity?.providerUserId}</Link>
Hello, <Link to="/profile">{getName(user)}</Link>
</div>
<div>
<button className="btn btn-primary" onClick={logout}>
19 changes: 9 additions & 10 deletions waspc/examples/todoApp/src/client/pages/ProfilePage.tsx
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import {
useSocketListener,
ServerToClientPayload,
} from '@wasp/webSocket'
import { getName, getProviderData } from '../user'

async function fetchCustomRoute() {
const res = await api.get('/foo/bar')
@@ -44,21 +45,19 @@ export const ProfilePage = ({ user }: { user: User }) => {
))
const connectionIcon = isConnected ? '🟢' : '🔴'

const identity = user.auth?.identities[0]

const userId = identity?.providerUserId

const isVerified =
identity?.providerData && 'isEmailVerified' in identity?.providerData
? identity?.providerData.isEmailVerified
: false
const providerData = getProviderData(user)

return (
<>
<h2>Profile page</h2>
<div>
Hello <strong>{userId}</strong>! Your status is{' '}
<strong>{isVerified ? 'verfied' : 'unverified'}</strong>.
Hello <strong>{getName(user)}</strong>! Your status is{' '}
<strong>
{providerData && providerData.isEmailVerified
? 'verfied'
: 'unverified'}
</strong>
.
</div>
<br />
<Link to="/task/:id" params={{ id: 3 }}>
33 changes: 33 additions & 0 deletions waspc/examples/todoApp/src/client/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { User } from '@wasp/auth/types'
import { findUserIdentity, getEmail } from '@wasp/auth/user'

export function getName(user?: User) {
infomiho marked this conversation as resolved.
Show resolved Hide resolved
if (!user) {
return null
}

// We use multiple auth methods, so we need to check which one is available.
const emailIdentity = findUserIdentity(user, 'email')
if (emailIdentity) {
return getEmail(user)
}

const googleIdentity = findUserIdentity(user, 'google')
if (googleIdentity) {
return `Google user ${googleIdentity.providerUserId}`
}

// If we don't know how to get the name, return null.
return null
}

export function getProviderData(user?: User) {
if (!user) {
return null
}

const emailIdentity = findUserIdentity(user, 'email')
return emailIdentity && 'isEmailVerified' in emailIdentity.providerData
? emailIdentity.providerData
: null
}
5 changes: 4 additions & 1 deletion waspc/headless-test/examples/todoApp/src/client/App.tsx
Original file line number Diff line number Diff line change
@@ -6,11 +6,14 @@ import { useQuery } from '@wasp/queries'
import getDate from '@wasp/queries/getDate'

import './Main.css'
import { getName } from './user'

export function App({ children }: any) {
const { data: user } = useAuth()
const { data: date } = useQuery(getDate)

const name = user ? getName(user) : null

return (
<div className="app border-spacing-2 p-4">
<header className="flex justify-between">
@@ -21,7 +24,7 @@ export function App({ children }: any) {
{user && (
<div className="flex gap-3 items-center">
<div>
Hello, <Link to="/profile">{user.email}</Link>
Hello, <Link to="/profile">{name}</Link>
</div>
<div>
<button className="btn btn-primary" onClick={logout}>
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
import React, { useEffect } from 'react'
import { Link } from '@wasp/router'
import { User } from '@wasp/entities'
import { User } from '@wasp/auth/types'
import api from '@wasp/api'
import { getName, getProviderData } from '../user'

async function fetchCustomRoute() {
const res = await api.get('/foo/bar')
console.log(res.data)
}

export const ProfilePage = ({ user }: { user: any }) => {
export const ProfilePage = ({ user }: { user: User }) => {
useEffect(() => {
fetchCustomRoute()
}, [])

const email = user.auth.identities.find(
(i: any) => i.providerName === 'email'
)?.providerUserId
const isEmailVerified = JSON.parse(
user.auth.identities.find((i: any) => i.providerName === 'email')
?.providerData
).isEmailVerified

console.log(user.auth.identities)
const name = getName(user)
const providerData = getProviderData(user)

return (
<>
<h2>Profile page</h2>
<div>
Hello <strong>{email}</strong>! Your status is{' '}
<strong>{isEmailVerified ? 'verfied' : 'unverified'}</strong>.
Hello <strong>{name}</strong>! Your status is{' '}
<strong>
{providerData && providerData.isEmailVerified
? 'verfied'
: 'unverified'}
</strong>
.
</div>
<br />
<Link to="/">Go to dashboard</Link>
33 changes: 33 additions & 0 deletions waspc/headless-test/examples/todoApp/src/client/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { User } from '@wasp/auth/types'
import { findUserIdentity, getEmail } from '@wasp/auth/user'

export function getName(user?: User) {
if (!user) {
return null
}

// We use multiple auth methods, so we need to check which one is available.
const emailIdentity = findUserIdentity(user, 'email')
if (emailIdentity) {
return getEmail(user)
}

const googleIdentity = findUserIdentity(user, 'google')
if (googleIdentity) {
return `Google user ${googleIdentity.providerUserId}`
}

// If we don't know how to get the name, return null.
return null
}

export function getProviderData(user?: User) {
if (!user) {
return null
}

const emailIdentity = findUserIdentity(user, 'email')
return emailIdentity && 'isEmailVerified' in emailIdentity.providerData
? emailIdentity.providerData
: null
}
Loading