feat: add auth via google

This commit is contained in:
Sonny
2024-04-27 18:14:40 +02:00
committed by Sonny
parent 2531242615
commit df4185bd62
18 changed files with 450 additions and 46 deletions

View File

@@ -12,3 +12,4 @@ DB_PASSWORD=my-links-pwd
DB_DATABASE=my-links
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_CLIENT_CALLBACK_URL=http://localhost:3333/auth/callback

View File

@@ -38,6 +38,7 @@ export default defineConfig({
() => import('@adonisjs/lucid/database_provider'),
() => import('@adonisjs/auth/auth_provider'),
() => import('@adonisjs/inertia/inertia_provider'),
() => import('@adonisjs/ally/ally_provider'),
],
/*

View File

@@ -0,0 +1,7 @@
import type { HttpContext } from '@adonisjs/core/http';
export default class AppsController {
index({ inertia }: HttpContext) {
return inertia.render('home');
}
}

View File

@@ -0,0 +1,56 @@
import User from '#models/user';
import type { HttpContext } from '@adonisjs/core/http';
import logger from '@adonisjs/core/services/logger';
export default class UsersController {
private redirectTo = '/';
google = ({ ally }: HttpContext) => ally.use('google').redirect();
async callbackAuth({ ally, auth, response, session }: HttpContext) {
const google = ally.use('google');
if (google.accessDenied()) {
// TODO: translate error messages + show them in UI
session.flash('flash', 'Access was denied');
return response.redirect(this.redirectTo);
}
if (google.stateMisMatch()) {
session.flash('flash', 'Request expired. Retry again');
return response.redirect(this.redirectTo);
}
if (google.hasError()) {
session.flash('flash', google.getError() || 'Something went wrong');
return response.redirect(this.redirectTo);
}
const { email, id: providerId, name, nickName, avatarUrl, token } = await google.user();
const user = await User.updateOrCreate(
{
email,
},
{
email,
providerId,
name,
nickName,
avatarUrl,
token,
}
);
await auth.use('web').login(user);
session.flash('flash', 'Successfully authenticated');
logger.info(`[${user.email}] auth success`);
response.redirect('/');
}
async logout({ auth, response, session }: HttpContext) {
await auth.use('web').logout();
session.flash('flash', 'Successfully disconnected');
logger.info(`[${auth.user?.email}] disconnected successfully`);
response.redirect('/');
}
}

View File

@@ -0,0 +1,5 @@
import { BaseModel, CamelCaseNamingStrategy } from '@adonisjs/lucid/orm';
export default class AppBaseModel extends BaseModel {
static namingStrategy = new CamelCaseNamingStrategy();
}

View File

@@ -1,30 +1,53 @@
import type { GoogleToken } from '@adonisjs/ally/types';
import { beforeCreate, column } from '@adonisjs/lucid/orm';
import { DateTime } from 'luxon';
import hash from '@adonisjs/core/services/hash';
import { compose } from '@adonisjs/core/helpers';
import { BaseModel, column } from '@adonisjs/lucid/orm';
import { withAuthFinder } from '@adonisjs/auth/mixins/lucid';
import { v4 as uuidv4 } from 'uuid';
import AppBaseModel from './app_base_model.js';
const AuthFinder = withAuthFinder(() => hash.use('scrypt'), {
uids: ['email'],
passwordColumnName: 'password',
});
export default class User extends AppBaseModel {
static selfAssignPrimaryKey = true;
export default class User extends compose(BaseModel, AuthFinder) {
@column({ isPrimary: true })
declare id: number;
@column()
declare fullName: string | null;
declare id: string; // UUID
@column()
declare email: string;
@column()
declare password: string;
declare name: string;
@column.dateTime({ autoCreate: true })
@column({ serializeAs: 'nickName' })
declare nickName: string; // public username
@column({ serializeAs: 'avatarUrl' })
declare avatarUrl: string;
declare isAdmin: boolean;
@column({ serializeAs: null })
declare token: GoogleToken;
@column({ serializeAs: null })
declare providerId: string;
@column.dateTime({
autoCreate: true,
serialize: (value: DateTime) => value.toISODate(),
serializeAs: 'createdAt',
})
declare createdAt: DateTime;
@column.dateTime({ autoCreate: true, autoUpdate: true })
declare updatedAt: DateTime | null;
@column.dateTime({
autoCreate: true,
autoUpdate: true,
serialize: (value: DateTime) => value.toISODate(),
serializeAs: 'updatedAt',
})
declare updatedAt: DateTime;
@beforeCreate()
static assignUuid(user: User) {
user.id = uuidv4();
user.isAdmin = false;
}
}

19
config/ally.ts Normal file
View File

@@ -0,0 +1,19 @@
import env from '#start/env';
import { defineConfig, services } from '@adonisjs/ally';
const allyConfig = defineConfig({
google: services.google({
clientId: env.get('GOOGLE_CLIENT_ID'),
clientSecret: env.get('GOOGLE_CLIENT_SECRET'),
callbackUrl: env.get('GOOGLE_CLIENT_CALLBACK_URL'),
prompt: 'select_account',
display: 'page',
scopes: ['userinfo.email', 'userinfo.profile'],
}),
});
export default allyConfig;
declare module '@adonisjs/ally/types' {
interface SocialProviders extends InferSocialProviders<typeof allyConfig> {}
}

View File

@@ -11,6 +11,13 @@ export default defineConfig({
*/
sharedData: {
errors: (ctx) => ctx.session?.flashMessages.get('errors'),
auth: async (ctx) => {
await ctx.auth.check();
return {
user: ctx.auth.user,
isAuthenticated: ctx.auth.isAuthenticated,
};
},
},
/**

View File

@@ -5,10 +5,15 @@ export default class extends BaseSchema {
async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id').notNullable();
table.string('full_name').nullable();
table.string('id').notNullable();
table.string('email', 254).notNullable().unique();
table.string('password').notNullable();
table.string('name', 254).notNullable();
table.string('nick_name', 254).notNullable();
table.text('avatar_url').notNullable();
table.boolean('is_admin').defaultTo(0).notNullable();
table.json('token').notNullable();
table.string('provider_id').notNullable();
table.timestamp('created_at').notNullable();
table.timestamp('updated_at').nullable();

View File

@@ -1,7 +1,9 @@
import '../css/app.css';
import { hydrateRoot } from 'react-dom/client';
import { createInertiaApp } from '@inertiajs/react';
/// <reference path="../../adonisrc.ts" />
import { resolvePageComponent } from '@adonisjs/inertia/helpers';
import { createInertiaApp } from '@inertiajs/react';
import { hydrateRoot } from 'react-dom/client';
import '../css/app.css';
const appName = import.meta.env.VITE_APP_NAME || 'AdonisJS';

View File

@@ -0,0 +1,5 @@
import { usePage } from '@inertiajs/react';
import type { InertiaPage } from '~/types/inertia';
const useUser = () => usePage<InertiaPage>().props.auth;
export default useUser;

View File

@@ -1,17 +1,28 @@
import { InferPageProps } from '@adonisjs/inertia/types';
import { Head } from '@inertiajs/react';
import useUser from '~/hooks/use_user';
import type AppsController from '../../app/controllers/apps_controller';
export default function Home(_: InferPageProps<AppsController, 'index'>) {
const { isAuthenticated, user } = useUser();
export default function Home(props: { version: number }) {
return (
<>
<Head title="Homepage" />
<div className="container">
<div className="title">AdonisJS {props.version} x Inertia x React</div>
<div className="title">AdonisJS x Inertia x React</div>
<span>
Learn more about AdonisJS and Inertia.js by visiting the{' '}
<a href="https://docs.adonisjs.com/guides/inertia">AdonisJS documentation</a>.
</span>
<span>{isAuthenticated ? 'Authenticated' : 'Not authenticated'}</span>
<span>
{isAuthenticated ? <a href="/auth/logout">Logout</a> : <a href="/auth/login">Login</a>}
</span>
<pre>{JSON.stringify(user, null, 2)}</pre>
</div>
</>
);

4
inertia/types/app.d.ts vendored Normal file
View File

@@ -0,0 +1,4 @@
import { Serialize } from '@tuyau/utils/types';
import type UserModel from '../../app/models/user';
type User = Serialize<UserModel>;

8
inertia/types/inertia.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
import type { User } from './app';
export type InertiaPage<T extends Record<string, unknown> = Record<string, unknown>> = T & {
auth: {
user?: User;
isAuthenticated: boolean;
};
};

259
package-lock.json generated
View File

@@ -9,6 +9,7 @@
"version": "0.0.0",
"license": "UNLICENSED",
"dependencies": {
"@adonisjs/ally": "^5.0.2",
"@adonisjs/auth": "^9.2.0",
"@adonisjs/core": "^6.8.0",
"@adonisjs/cors": "^2.2.1",
@@ -25,7 +26,8 @@
"pg": "^8.11.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"reflect-metadata": "^0.2.2"
"reflect-metadata": "^0.2.2",
"uuid": "^9.0.1"
},
"devDependencies": {
"@adonisjs/assembler": "^7.5.1",
@@ -39,6 +41,7 @@
"@types/node": "^20.12.7",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^9.0.8",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"hot-hook": "^0.2.1",
@@ -70,6 +73,21 @@
"node": ">=18.16.0"
}
},
"node_modules/@adonisjs/ally": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/@adonisjs/ally/-/ally-5.0.2.tgz",
"integrity": "sha512-/A53dXiFwwwi9SM8U5dIffesCcNbklHqoME8zHYYO4KQ+dzg9CnubBtgcvH1XRJV8v52FgyUnPFFHDd8J3zI9A==",
"dependencies": {
"@poppinss/oauth-client": "^5.1.2",
"@poppinss/utils": "^6.7.1"
},
"engines": {
"node": ">=18.16.0"
},
"peerDependencies": {
"@adonisjs/core": "^6.2.0"
}
},
"node_modules/@adonisjs/application": {
"version": "8.2.2",
"resolved": "https://registry.npmjs.org/@adonisjs/application/-/application-8.2.2.tgz",
@@ -436,6 +454,11 @@
}
}
},
"node_modules/@adonisjs/inertia/node_modules/@tuyau/utils": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@tuyau/utils/-/utils-0.0.1.tgz",
"integrity": "sha512-Vi2uT9yuy0jZkaW0c1nMgja266DcIoF+/UK0HGMlTH/FUrmKiQLtu64PKBKZtibkezN4nlw3po4SZKvH37SklA=="
},
"node_modules/@adonisjs/logger": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/@adonisjs/logger/-/logger-6.0.3.tgz",
@@ -2111,6 +2134,18 @@
"uid-safe": "2.1.5"
}
},
"node_modules/@poppinss/oauth-client": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/@poppinss/oauth-client/-/oauth-client-5.1.3.tgz",
"integrity": "sha512-cjgac/0pwk/J+x1Jei/cAHTzstCuZE7KRfmdVhClb9zMUskw477rZPZ86dg1LBghw+IGaPtnAgmxTV9pNWG9ZQ==",
"dependencies": {
"@poppinss/utils": "^6.7.3",
"got": "^14.2.1"
},
"engines": {
"node": ">=18.16.0"
}
},
"node_modules/@poppinss/prompts": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/@poppinss/prompts/-/prompts-3.1.3.tgz",
@@ -2560,6 +2595,17 @@
"@swc/counter": "^0.1.3"
}
},
"node_modules/@szmarczak/http-timer": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz",
"integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==",
"dependencies": {
"defer-to-connect": "^2.0.1"
},
"engines": {
"node": ">=14.16"
}
},
"node_modules/@tokenizer/token": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
@@ -2601,11 +2647,6 @@
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true
},
"node_modules/@tuyau/utils": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/@tuyau/utils/-/utils-0.0.1.tgz",
"integrity": "sha512-Vi2uT9yuy0jZkaW0c1nMgja266DcIoF+/UK0HGMlTH/FUrmKiQLtu64PKBKZtibkezN4nlw3po4SZKvH37SklA=="
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@@ -2668,6 +2709,11 @@
"resolved": "https://registry.npmjs.org/@types/he/-/he-1.2.3.tgz",
"integrity": "sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA=="
},
"node_modules/@types/http-cache-semantics": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
"integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="
},
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -2760,6 +2806,12 @@
"integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
"dev": true
},
"node_modules/@types/uuid": {
"version": "9.0.8",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz",
"integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==",
"dev": true
},
"node_modules/@types/validator": {
"version": "13.11.9",
"resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.9.tgz",
@@ -3585,6 +3637,42 @@
"node": ">=8"
}
},
"node_modules/cacheable-lookup": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz",
"integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==",
"engines": {
"node": ">=14.16"
}
},
"node_modules/cacheable-request": {
"version": "10.2.14",
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz",
"integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==",
"dependencies": {
"@types/http-cache-semantics": "^4.0.2",
"get-stream": "^6.0.1",
"http-cache-semantics": "^4.1.1",
"keyv": "^4.5.3",
"mimic-response": "^4.0.0",
"normalize-url": "^8.0.0",
"responselike": "^3.0.0"
},
"engines": {
"node": ">=14.16"
}
},
"node_modules/cacheable-request/node_modules/get-stream": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/call-bind": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
@@ -4272,6 +4360,31 @@
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
"dev": true
},
"node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dependencies": {
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/decompress-response/node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/dedent": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
@@ -4330,6 +4443,14 @@
"node": ">=0.8"
}
},
"node_modules/defer-to-connect": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
"engines": {
"node": ">=10"
}
},
"node_modules/define-data-property": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
@@ -5481,6 +5602,14 @@
"node": ">= 6"
}
},
"node_modules/form-data-encoder": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz",
"integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==",
"engines": {
"node": ">= 18"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -5636,7 +5765,6 @@
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"devOptional": true,
"engines": {
"node": ">=16"
},
@@ -5789,6 +5917,30 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/got": {
"version": "14.2.1",
"resolved": "https://registry.npmjs.org/got/-/got-14.2.1.tgz",
"integrity": "sha512-KOaPMremmsvx6l9BLC04LYE6ZFW4x7e4HkTe3LwBmtuYYQwpeS4XKqzhubTIkaQ1Nr+eXxeori0zuwupXMovBQ==",
"dependencies": {
"@sindresorhus/is": "^6.1.0",
"@szmarczak/http-timer": "^5.0.1",
"cacheable-lookup": "^7.0.0",
"cacheable-request": "^10.2.14",
"decompress-response": "^6.0.0",
"form-data-encoder": "^4.0.2",
"get-stream": "^8.0.1",
"http2-wrapper": "^2.2.1",
"lowercase-keys": "^3.0.0",
"p-cancelable": "^4.0.1",
"responselike": "^3.0.0"
},
"engines": {
"node": ">=20"
},
"funding": {
"url": "https://github.com/sindresorhus/got?sponsor=1"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
@@ -5939,6 +6091,11 @@
}
]
},
"node_modules/http-cache-semantics": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
"integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ=="
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -5954,6 +6111,18 @@
"node": ">= 0.8"
}
},
"node_modules/http2-wrapper": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz",
"integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==",
"dependencies": {
"quick-lru": "^5.1.1",
"resolve-alpn": "^1.2.0"
},
"engines": {
"node": ">=10.19.0"
}
},
"node_modules/human-signals": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
@@ -6673,8 +6842,7 @@
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
"dev": true
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="
},
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
@@ -6767,7 +6935,6 @@
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
"dependencies": {
"json-buffer": "3.0.1"
}
@@ -7029,6 +7196,17 @@
"get-func-name": "^2.0.1"
}
},
"node_modules/lowercase-keys": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz",
"integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/lru-cache": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.1.tgz",
@@ -7184,6 +7362,17 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mimic-response": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz",
"integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==",
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/min-indent": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
@@ -7462,6 +7651,14 @@
"node": ">= 0.8.0"
}
},
"node_modules/p-cancelable": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz",
"integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==",
"engines": {
"node": ">=14.16"
}
},
"node_modules/p-event": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz",
@@ -8150,6 +8347,17 @@
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
},
"node_modules/quick-lru": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
@@ -8580,6 +8788,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/resolve-alpn": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
@@ -8589,6 +8802,20 @@
"node": ">=4"
}
},
"node_modules/responselike": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz",
"integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==",
"dependencies": {
"lowercase-keys": "^3.0.0"
},
"engines": {
"node": ">=14.16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/restore-cursor": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz",
@@ -9909,6 +10136,18 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/uuid": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
],
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",

View File

@@ -43,6 +43,7 @@
"@types/node": "^20.12.7",
"@types/react": "^18.3.1",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^9.0.8",
"@vitejs/plugin-react": "^4.2.1",
"eslint": "^8.57.0",
"hot-hook": "^0.2.1",
@@ -53,6 +54,7 @@
"vite": "^5.2.10"
},
"dependencies": {
"@adonisjs/ally": "^5.0.2",
"@adonisjs/auth": "^9.2.0",
"@adonisjs/core": "^6.8.0",
"@adonisjs/cors": "^2.2.1",
@@ -69,7 +71,8 @@
"pg": "^8.11.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"reflect-metadata": "^0.2.2"
"reflect-metadata": "^0.2.2",
"uuid": "^9.0.1"
},
"hotHook": {
"boundaries": [

View File

@@ -35,4 +35,13 @@ export default await Env.create(new URL('../', import.meta.url), {
DB_USER: Env.schema.string(),
DB_PASSWORD: Env.schema.string.optional(),
DB_DATABASE: Env.schema.string(),
/*
|----------------------------------------------------------
| Variables for configuring ally package
|----------------------------------------------------------
*/
GOOGLE_CLIENT_ID: Env.schema.string(),
GOOGLE_CLIENT_SECRET: Env.schema.string(),
GOOGLE_CLIENT_CALLBACK_URL: Env.schema.string(),
});

View File

@@ -1,11 +1,10 @@
/*
|--------------------------------------------------------------------------
| Routes file
|--------------------------------------------------------------------------
|
| The routes file is used for defining the HTTP routes.
|
*/
import router from '@adonisjs/core/services/router';
router.on('/inertia').renderInertia('home', { version: 6 });
const UsersController = () => import('#controllers/users_controller');
const AppsController = () => import('#controllers/apps_controller');
router.get('/', [AppsController, 'index']);
router.get('/auth/login', [UsersController, 'google']);
router.get('/auth/callback', [UsersController, 'callbackAuth']);
router.get('/auth/logout', [UsersController, 'logout']);