Skip to content

Commit

Permalink
refactor: improve social auth setup
Browse files Browse the repository at this point in the history
  • Loading branch information
AdrianAndersen committed Jan 25, 2025
1 parent da66a29 commit 3c33fea
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 88 deletions.
13 changes: 13 additions & 0 deletions backend/app/controllers/auth/social_controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { HttpContext } from "@adonisjs/core/http";

import AuthSocialService from "#services/auth_social_service";

export default class SocialController {
async redirect({ ally, params }: HttpContext) {
await ally.use(params["provider"]).redirect();
}

async callback(ctx: HttpContext) {
await AuthSocialService.handleCallback(ctx);
}
}
27 changes: 5 additions & 22 deletions backend/app/services/auth/user/user-provider.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,23 @@
import LocalLoginHandler from "#services/auth/local/local-login.handler";
import TokenHandler from "#services/auth/token/token.handler";
import UserHandler from "#services/auth/user/user.handler";
import { User } from "#services/types/user";

async function getUser(
async function loginOrCreate(
username: string,
provider: string,
providerId: string,
): Promise<User> {
let user;
) {
try {
user = await UserHandler.get(provider, providerId);
await UserHandler.get(provider, providerId);
} catch {
user = await UserHandler.create(username, provider, providerId);
await UserHandler.create(username, provider, providerId);
}

return user;
}

async function loginOrCreate(
username: string,
provider: string,
providerId: string,
): Promise<{
user: User;
tokens: { accessToken: string; refreshToken: string };
}> {
const user = await getUser(username, provider, providerId);

await UserHandler.valid(username);

await LocalLoginHandler.createDefaultLocalLoginIfNoneIsFound(username);

const tokens = await TokenHandler.createTokens(username);

return { user: user, tokens: tokens };
return await TokenHandler.createTokens(username);
}

const UserProvider = {
Expand Down
35 changes: 35 additions & 0 deletions backend/app/services/auth_social_service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { SocialProviders } from "@adonisjs/ally/types";
import { HttpContext } from "@adonisjs/core/http";

import UserProvider from "#services/auth/user/user-provider";
import { retrieveRefererPath } from "#services/config/api-path";
import { BlEnv } from "#services/config/env";

async function handleCallback(ctx: HttpContext) {
const provider: keyof SocialProviders = ctx.params["provider"];
const social = ctx.ally.use(provider);

if (social.accessDenied() || social.stateMisMatch() || social.hasError()) {
return ctx.response.redirect(`${BlEnv.CLIENT_URI}auth/social/failure`);
}

const user = await social.user();

const { accessToken, refreshToken } = await UserProvider.loginOrCreate(
user.email,
provider,
user.id,
);

return ctx.response.redirect(
`${
retrieveRefererPath(ctx.request.headers()) ?? BlEnv.CLIENT_URI
}auth/token?access_token=${accessToken}&refresh_token=${refreshToken}`,
);
}

const AuthSocialService = {
handleCallback,
};

export default AuthSocialService;
74 changes: 12 additions & 62 deletions backend/start/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,72 +6,22 @@ import * as Sentry from "@sentry/node";
import configureMongoose from "#config/database";
import LocalAuth from "#services/auth/local/local.auth";
import TokenEndpoint from "#services/auth/token/token.endpoint";
import UserProvider from "#services/auth/user/user-provider";
import CollectionEndpointCreator from "#services/collection-endpoint/collection-endpoint-creator";
import { retrieveRefererPath } from "#services/config/api-path";
import { APP_CONFIG } from "#services/config/application-config";
import setupPassport from "#services/config/auth";
import { BlEnv } from "#services/config/env";

router.get("/auth/facebook", ({ ally }) => {
return ally.use("facebook").redirect();
});
router.get("/auth/facebook/callback", async ({ ally, request, response }) => {
const fb = ally.use("facebook");
if (fb.accessDenied()) {
return "You have cancelled the login process";
}
if (fb.stateMisMatch()) {
return "We are unable to verify the request. Please try again";
}

if (fb.hasError()) {
return fb.getError();
}

const user = await fb.user();
const provider = APP_CONFIG.login.facebook.name;

const userAndTokens = await UserProvider.loginOrCreate(
user.email,
provider,
user.id,
);
const redirectUrl = `${
retrieveRefererPath(request.headers()) ?? BlEnv.CLIENT_URI
}auth/token?access_token=${userAndTokens.tokens.accessToken}&refresh_token=${userAndTokens.tokens.refreshToken}`;
return response.redirect(redirectUrl);
});

router.get("/auth/google", ({ ally }) => {
return ally.use("google").redirect();
});
router.get("/auth/google/callback", async ({ ally, request, response }) => {
const google = ally.use("google");
if (google.accessDenied()) {
return "You have cancelled the login process";
}
if (google.stateMisMatch()) {
return "We are unable to verify the request. Please try again";
}

if (google.hasError()) {
return google.getError();
}

const user = await google.user();
const provider = APP_CONFIG.login.google.name;

const userAndTokens = await UserProvider.loginOrCreate(
user.email,
provider,
user.id,
);
const redirectUrl = `${
retrieveRefererPath(request.headers()) ?? BlEnv.CLIENT_URI
}auth/token?access_token=${userAndTokens.tokens.accessToken}&refresh_token=${userAndTokens.tokens.refreshToken}`;
return response.redirect(redirectUrl);
});
const AuthSocialController = () =>
import("#controllers/auth/social_controller");

/**
* auth social
*/
router
.get("/auth/:provider/redirect", [AuthSocialController, "redirect"])
.as("auth.social.redirect");
router
.get("/auth/:provider/callback", [AuthSocialController, "callback"])
.as("auth.social.callback");

setupPassport();
LocalAuth.generateEndpoints();
Expand Down
4 changes: 2 additions & 2 deletions backend/tests/user-provider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ test.group("UserProvider", (group) => {

return expect(
UserProvider.loginOrCreate("[email protected]", "local", "abcdefg"),
).to.eventually.be.eql({ user: user, tokens: tokens });
).to.eventually.be.eql(tokens);
});

test("loginOrCreate() - should resolve with a user object and tokens", async () => {
Expand All @@ -93,6 +93,6 @@ test.group("UserProvider", (group) => {

return expect(
UserProvider.loginOrCreate("[email protected]", "local", "abcdefg"),
).to.eventually.be.eql({ user: user, tokens: tokens });
).to.eventually.be.eql(tokens);
});
});
4 changes: 2 additions & 2 deletions frontend/src/utils/bl-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ const BL_CONFIG = {
url: "auth/local/login",
},
facebook: {
url: "auth/facebook",
url: "auth/facebook/redirect",
},
google: {
url: "auth/google",
url: "auth/google/redirect",
},
localStorageKeys: {
redirect: "bl-redirect",
Expand Down

0 comments on commit 3c33fea

Please sign in to comment.