refactor #26
@ -10,25 +10,15 @@ export interface ClientInfoHeader {
|
|||||||
ip: string;
|
ip: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUserHeaderInformation = (
|
export const getUserHeaderInformation = (ctx: Context): UserHeaderInformation => {
|
||||||
ctx: Context,
|
|
||||||
): UserHeaderInformation => {
|
|
||||||
const clientInfoHeader =
|
const clientInfoHeader =
|
||||||
(JSON.parse(
|
(JSON.parse(ctx.request.headers.get("x-client-info") as string) as ClientInfoHeader) ?? ("unknown" as string);
|
||||||
ctx.request.headers.get("x-client-info") as string,
|
|
||||||
) as ClientInfoHeader) ?? ("unknown" as string);
|
|
||||||
|
|
||||||
const userHeaderInformation = {
|
const userHeaderInformation = {
|
||||||
ip: clientInfoHeader.ip ?? "unknown",
|
ip: clientInfoHeader.ip ?? "unknown",
|
||||||
deviceType: clientInfoHeader.deviceType ?? "unknown",
|
deviceType: clientInfoHeader.deviceType ?? "unknown",
|
||||||
deviceOS:
|
deviceOS: (clientInfoHeader.os ?? "unknown") + " " + (clientInfoHeader.osVersion ?? "unknown"),
|
||||||
(clientInfoHeader.os ?? "unknown") +
|
browser: (clientInfoHeader.browser ?? "unknown") + " " + (clientInfoHeader.browserVersion ?? "unknown"),
|
||||||
" " +
|
|
||||||
(clientInfoHeader.osVersion ?? "unknown"),
|
|
||||||
browser:
|
|
||||||
(clientInfoHeader.browser ?? "unknown") +
|
|
||||||
" " +
|
|
||||||
(clientInfoHeader.browserVersion ?? "unknown"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return userHeaderInformation;
|
return userHeaderInformation;
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { googleCallbackService } from "../services/http/googleCallback.service";
|
|||||||
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
|
import { getUserHeaderInformation } from "../../../helpers/http/userHeader/getUserHeaderInformation";
|
||||||
|
|
||||||
export const googleCallbackController = async (
|
export const googleCallbackController = async (
|
||||||
ctx: Context & { query: { code: string; state: string; callbackURI: string } }
|
ctx: Context & { query: { code: string; state: string; callbackURI: string } },
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const userHeaderInfo = getUserHeaderInformation(ctx);
|
const userHeaderInfo = getUserHeaderInformation(ctx);
|
||||||
|
|||||||
@ -1,14 +1,16 @@
|
|||||||
import { Context } from "elysia";
|
import { Context, Static } from "elysia";
|
||||||
import { mainErrorHandler } from "../../../helpers/error/handler";
|
import { mainErrorHandler } from "../../../helpers/error/handler";
|
||||||
import { googleRequestService } from "../services/http/googleRequest.service";
|
import { googleRequestService } from "../services/http/googleRequest.service";
|
||||||
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
import { returnReadResponse } from "../../../helpers/callback/httpResponse";
|
||||||
|
import { googleRequestSchema } from "../schemas/googleRequest.schema";
|
||||||
|
|
||||||
export const googleRequestController = async (
|
export const googleRequestController = async (ctx: {
|
||||||
ctx: Context & { query: { callback?: string } }
|
set: Context["set"];
|
||||||
) => {
|
query: Static<typeof googleRequestSchema.query>;
|
||||||
|
}) => {
|
||||||
try {
|
try {
|
||||||
const loginUrl = await googleRequestService(ctx.query.callback);
|
const loginUrl = await googleRequestService(ctx.query.callback);
|
||||||
return returnReadResponse(ctx.set, 200, "Google login url created!", {
|
return returnReadResponse(ctx.set, 200, "Google login URL created successfully.", {
|
||||||
endpointUrl: loginUrl,
|
endpointUrl: loginUrl,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -9,13 +9,16 @@ import { tokenValidationController } from "./controllers/tokenValidation.control
|
|||||||
import { logoutController } from "./controllers/logout.controller";
|
import { logoutController } from "./controllers/logout.controller";
|
||||||
import { tokenValidationSchema } from "./schemas/tokenValidation.schema";
|
import { tokenValidationSchema } from "./schemas/tokenValidation.schema";
|
||||||
import { getOauthProvidersSchema } from "./schemas/getOauthProviders.schema";
|
import { getOauthProvidersSchema } from "./schemas/getOauthProviders.schema";
|
||||||
|
import { getCallbackProviderUrlSchema } from "./schemas/getCallbackProviderUrl.schema";
|
||||||
|
import { googleRequestSchema } from "./schemas/googleRequest.schema";
|
||||||
|
import { googleCallbackSchema } from "./schemas/googleCallback.schema";
|
||||||
|
|
||||||
export const authModule = new Elysia({ prefix: "/auth", tags: ["Authentication"] })
|
export const authModule = new Elysia({ prefix: "/auth", tags: ["Authentication"] })
|
||||||
.post("/token/validate", tokenValidationController, tokenValidationSchema)
|
.post("/token/validate", tokenValidationController, tokenValidationSchema)
|
||||||
.get("/providers", getOauthProvidersController, getOauthProvidersSchema)
|
.get("/providers", getOauthProvidersController, getOauthProvidersSchema)
|
||||||
.get("/providers/:name/callback", getCallbackProviderUrlController)
|
.get("/providers/:name/callback", getCallbackProviderUrlController, getCallbackProviderUrlSchema)
|
||||||
|
.get("/google", googleRequestController, googleRequestSchema)
|
||||||
|
.get("/google/callback", googleCallbackController, googleCallbackSchema)
|
||||||
.get("/github", githubRequestController)
|
.get("/github", githubRequestController)
|
||||||
.get("/github/callback", githubCallbackController)
|
.get("/github/callback", githubCallbackController)
|
||||||
.get("/google", googleRequestController)
|
|
||||||
.get("/google/callback", googleCallbackController)
|
|
||||||
.post("/logout", logoutController);
|
.post("/logout", logoutController);
|
||||||
|
|||||||
45
src/modules/auth/schemas/getCallbackProviderUrl.schema.ts
Normal file
45
src/modules/auth/schemas/getCallbackProviderUrl.schema.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
||||||
|
|
||||||
|
export const getCallbackProviderUrlSchema = {
|
||||||
|
detail: {
|
||||||
|
summary: "Get the callback URL of oauth provider",
|
||||||
|
description:
|
||||||
|
"After users have successfully completed the authentication process on the OAuth provider page, they will be redirected to the callback page on the frontend. This endpoint aims to obtain the actual endpoint for each OAuth response handler.",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "The callback URL on the provider has been found.",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: "number",
|
||||||
|
default: 200,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
default: "The callback URL on the provider has been found.",
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
callback_url: {
|
||||||
|
type: "string",
|
||||||
|
description: "The callback URL on the provider.",
|
||||||
|
example: "auth/google/callback",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies AppRouteSchema;
|
||||||
58
src/modules/auth/schemas/googleCallback.schema.ts
Normal file
58
src/modules/auth/schemas/googleCallback.schema.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { t } from "elysia";
|
||||||
|
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
||||||
|
|
||||||
|
export const googleCallbackSchema = {
|
||||||
|
headers: t.Object({
|
||||||
|
"x-client-info": t.String({
|
||||||
|
examples: [
|
||||||
|
'{"os":"Windows","osVersion":"10","browser":"Chrome","browserVersion":"89.0.4389.82","deviceType":"Desktop","ip":"192.168.1.1"}',
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
query: t.Object({
|
||||||
|
code: t.String({ examples: ["4/0AY0e-xxxxxxxxx"] }),
|
||||||
|
state: t.String({ examples: ["random_state_string"] }),
|
||||||
|
callbackURI: t.String({ examples: ["https://example.com/auth/google/callback"] }),
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "Google OAuth callback endpoint",
|
||||||
|
description:
|
||||||
|
"Handles the callback from Google OAuth and processes the authentication response. This endpoint also processes the account provisioning if the user is logging in for the first time.",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Authentication successful",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
example: true,
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: "number",
|
||||||
|
example: 200,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
example: "Authentication successful",
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
authToken: {
|
||||||
|
type: "string",
|
||||||
|
description: "JWT token for authenticated user",
|
||||||
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies AppRouteSchema;
|
||||||
54
src/modules/auth/schemas/googleRequest.schema.ts
Normal file
54
src/modules/auth/schemas/googleRequest.schema.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { t } from "elysia";
|
||||||
|
import { AppRouteSchema } from "../../../helpers/types/AppRouteSchema";
|
||||||
|
|
||||||
|
export const googleRequestSchema = {
|
||||||
|
query: t.Object({
|
||||||
|
callback: t.Optional(
|
||||||
|
t.String({
|
||||||
|
description: "The callback URL to redirect after Google authentication. It should be URL-encoded if provided.",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
detail: {
|
||||||
|
summary: "Initiate Google OAuth flow",
|
||||||
|
description:
|
||||||
|
"This endpoint initiates the Google OAuth flow by redirecting the user to Google's authentication page.",
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
description: "Google login URL created successfully.",
|
||||||
|
content: {
|
||||||
|
"application/json": {
|
||||||
|
schema: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
success: {
|
||||||
|
type: "boolean",
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
status: {
|
||||||
|
type: "number",
|
||||||
|
default: 200,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: "string",
|
||||||
|
default: "Google login URL created successfully.",
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
endpointUrl: {
|
||||||
|
type: "string",
|
||||||
|
description: "The URL to redirect the user for Google authentication.",
|
||||||
|
example:
|
||||||
|
"https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&scope=email%20profile",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} satisfies AppRouteSchema;
|
||||||
Reference in New Issue
Block a user