diff --git a/pages/pages/oauth/redirect.vue b/pages/pages/oauth/redirect.vue new file mode 100644 index 00000000..5a06fa51 --- /dev/null +++ b/pages/pages/oauth/redirect.vue @@ -0,0 +1,118 @@ + + + + + + + + + Allow this application to access your + account? + + {{ application }} + {{ website }} + + + + + This application will be able to: + + + + + + + + + {{ text[0] }} {{ text[1] }} + + + + + + You are signing in to {{ application }} with your + account. + This allows {{ application }} to perform the above account + actions. + + + + Authorize + Cancel + + + + + + + \ No newline at end of file diff --git a/pages/routes.ts b/pages/routes.ts index a39340ef..b15ef1e7 100644 --- a/pages/routes.ts +++ b/pages/routes.ts @@ -1,12 +1,14 @@ import type { RouteRecordRaw } from "vue-router"; import indexVue from "./pages/index.vue"; import authorizeVue from "./pages/oauth/authorize.vue"; +import redirectVue from "./pages/oauth/redirect.vue"; import registerIndexVue from "./pages/register/index.vue"; import successVue from "./pages/register/success.vue"; export default [ { path: "/", component: indexVue }, { path: "/oauth/authorize", component: authorizeVue }, + { path: "/oauth/redirect", component: redirectVue }, { path: "/register", component: registerIndexVue }, { path: "/register/success", component: successVue }, ] as RouteRecordRaw[]; diff --git a/routes.ts b/routes.ts index b8cc6424..eae9e028 100644 --- a/routes.ts +++ b/routes.ts @@ -34,6 +34,7 @@ export const rawRoutes = { "/api/v2/media": "./server/api/api/v2/media/index", "/api/v2/search": "./server/api/api/v2/search/index", "/auth/login": "./server/api/auth/login/index", + "/auth/redirect": "./server/api/auth/redirect/index", "/nodeinfo/2.0": "./server/api/nodeinfo/2.0/index", "/oauth/authorize-external": "./server/api/oauth/authorize-external/index", "/oauth/providers": "./server/api/oauth/providers/index", diff --git a/server/api/auth/login/index.ts b/server/api/auth/login/index.ts index 7b9094b6..db838537 100644 --- a/server/api/auth/login/index.ts +++ b/server/api/auth/login/index.ts @@ -89,6 +89,17 @@ export default apiRoute<{ }, }); - // Redirect back to application - return Response.redirect(`${redirect_uri}?code=${code}`, 302); + // Redirect to OAuth confirmation screen + return Response.redirect( + `/oauth/redirect?` + + new URLSearchParams({ + redirect_uri, + code, + client_id, + application: application.name, + website: application.website ?? "", + scope: scopes.join(" "), + }).toString(), + 302 + ); }); diff --git a/server/api/auth/redirect/index.ts b/server/api/auth/redirect/index.ts new file mode 100644 index 00000000..1b2efb2c --- /dev/null +++ b/server/api/auth/redirect/index.ts @@ -0,0 +1,58 @@ +import { apiRoute, applyConfig } from "@api"; +import { client } from "~database/datasource"; +import { userRelations } from "~database/entities/User"; + +export const meta = applyConfig({ + allowedMethods: ["POST"], + ratelimits: { + max: 4, + duration: 60, + }, + route: "/auth/redirect", + auth: { + required: false, + }, +}); + +/** + * OAuth Code flow + */ +export default apiRoute<{ + email: string; + password: string; +}>(async (req, matchedRoute) => { + const redirect_uri = decodeURIComponent(matchedRoute.query.redirect_uri); + const client_id = matchedRoute.query.client_id; + const code = matchedRoute.query.code; + + const redirectToLogin = (error: string) => + Response.redirect( + `/oauth/authorize?` + + new URLSearchParams({ + ...matchedRoute.query, + error: encodeURIComponent(error), + }).toString(), + 302 + ); + + // Get token + const token = await client.token.findFirst({ + where: { + code, + application: { + client_id, + }, + }, + include: { + user: { + include: userRelations, + }, + application: true, + }, + }); + + if (!token) return redirectToLogin("Invalid code"); + + // Redirect back to application + return Response.redirect(`${redirect_uri}?code=${code}`, 302); +}); diff --git a/server/api/oauth/callback/[issuer]/index.ts b/server/api/oauth/callback/[issuer]/index.ts index 15d905eb..c898ed28 100644 --- a/server/api/oauth/callback/[issuer]/index.ts +++ b/server/api/oauth/callback/[issuer]/index.ts @@ -184,7 +184,15 @@ export default apiRoute(async (req, matchedRoute, extraData) => { // Redirect back to application return Response.redirect( - `${flow.application.redirect_uris}?code=${code}`, + `/oauth/redirect?` + + new URLSearchParams({ + redirect_uri: flow.application.redirect_uris, + code, + client_id: flow.application.client_id, + application: flow.application.name, + website: flow.application.website ?? "", + scope: flow.application.scopes, + }).toString(), 302 ); });
You are signing in to {{ application }} with your + account.
This allows {{ application }} to perform the above account + actions.