console/integration-tests/testkit/auth.ts
Laurin Quast 6540155fc7
feat: replace auth0 with supertokens (#303)
* add supertoken container to docker-compose file

* yeah I am sorry this one big commit and I am ashamed of it

* use logOut function

* feat: show header on 404 page

* feat: better handling for organization cookie when not authenticated

* wrap it

* check session within server side props

* add is_admin flag user migration

* simplify and annotate the config

* fix: handle status codes + fix email/password sign up with import from auth0

* no hardcoded env pls

* decode process.env

* secure update user id mapping via a key

* fix: login form

* lol we don't need to hit the API

* fix: do graphql api authorization via authorization header instead of cookie

* implement isAdmin flag

* fix: types :)

* skipit

* yo we can run this

* set env variables

* disable because it annoys the hell out of me

* use the right host

* add not about token length

* refactor: decode environment variables

* feat: store external user id from guthub/google provider in the database

* workaround supertokens omitting null values from the token

* re-enable check

* i have no time for this shit

* add missing env variable

* fix: email test; missing domain extension

* configure pulumi deployment

Co-authored-by: Kamil Kisiela <kamil.kisiela@gmail.com>
Co-authored-by: Dotan Simha <dotansimha@gmail.com>

* configure pulumi deployment

Co-authored-by: Kamil Kisiela <kamil.kisiela@gmail.com>
Co-authored-by: Dotan Simha <dotansimha@gmail.com>

* configure pulumi deployment

Co-authored-by: Kamil Kisiela <kamil.kisiela@gmail.com>
Co-authored-by: Dotan Simha <dotansimha@gmail.com>

* configure pulumi deployment

Co-authored-by: Kamil Kisiela <kamil.kisiela@gmail.com>

* fix: env names

* fix: link google account to the correct db record

* feat: email confirmation emails

* ?

* bump ts-node

* fix types

* omit package form the bundle

* remove it from dependencies...

* add emails apckage to dev deps

* resolve eslint issues

* remove comments

* update dev info + change env variable (no need to expose it on the frontend)

* use correct user id lol

Co-authored-by: Kamil Kisiela <kamil.kisiela@gmail.com>
Co-authored-by: Dotan Simha <dotansimha@gmail.com>
2022-09-06 09:38:31 +02:00

111 lines
3.1 KiB
TypeScript

import { fetch } from 'cross-undici-fetch';
import zod from 'zod';
import { ensureEnv } from './env';
const SignUpSignInUserResponseModel = zod.object({
status: zod.literal('OK'),
user: zod.object({ email: zod.string(), id: zod.string(), timeJoined: zod.number() }),
});
const signUpUserViaEmail = async (
email: string,
password: string
): Promise<zod.TypeOf<typeof SignUpSignInUserResponseModel>> => {
const response = await fetch(`${ensureEnv('SUPERTOKENS_CONNECTION_URI')}/recipe/signup`, {
method: 'POST',
headers: {
'content-type': 'application/json; charset=UTF-8',
'api-key': ensureEnv('SUPERTOKENS_API_KEY'),
},
body: JSON.stringify({
email,
password,
}),
});
const body = await response.text();
if (response.status !== 200) {
throw new Error(`Signup failed. ${response.status}.\n ${body}`);
}
return SignUpSignInUserResponseModel.parse(JSON.parse(body));
};
const createSessionPayload = (superTokensUserId: string, email: string) => ({
version: '1',
superTokensUserId,
externalUserId: null,
email,
});
const CreateSessionModel = zod.object({
accessToken: zod.object({
token: zod.string(),
}),
refreshToken: zod.object({
token: zod.string(),
}),
idRefreshToken: zod.object({
token: zod.string(),
}),
});
const createSession = async (superTokensUserId: string, email: string) => {
const sessionData = createSessionPayload(superTokensUserId, email);
const payload = {
enableAntiCsrf: false,
userId: superTokensUserId,
userDataInDatabase: sessionData,
userDataInJWT: sessionData,
};
const response = await fetch(`${ensureEnv('SUPERTOKENS_CONNECTION_URI')}/recipe/session`, {
method: 'POST',
headers: {
'content-type': 'application/json; charset=UTF-8',
'api-key': ensureEnv('SUPERTOKENS_API_KEY'),
rid: 'session',
},
body: JSON.stringify(payload),
});
const body = await response.text();
if (response.status !== 200) {
throw new Error(`Create session failed. ${response.status}.\n ${body}`);
}
const data = CreateSessionModel.parse(JSON.parse(body));
/**
* These are the required cookies that need to be set.
*/
return {
access_token: data.accessToken.token,
};
};
type UserID = 'main' | 'extra' | 'admin';
const password = 'ilikebigturtlesandicannotlie47';
export const userEmails: Record<UserID, string> = {
main: 'main@localhost.localhost',
extra: 'extra@localhost.localhost',
admin: 'admin@localhost.localhost',
};
const tokenResponsePromise: Record<UserID, Promise<{ access_token: string }> | null> = {
main: null,
extra: null,
admin: null,
};
async function signUpAndSignInViaEmail(email: string, password: string): Promise<{ access_token: string }> {
const data = await signUpUserViaEmail(email, password);
return await createSession(data.user.id, data.user.email);
}
export function authenticate(userId: UserID): Promise<{ access_token: string }> {
if (!tokenResponsePromise[userId]) {
tokenResponsePromise[userId] = signUpAndSignInViaEmail(userEmails[userId], password);
}
return tokenResponsePromise[userId]!;
}