ekyc

Electronic KYC process with uploading ID document using OAuth 2.1 (experimental)
Log | Files | Refs | README | LICENSE

authorize.tsx (2716B)


      1 import { Link } from "#http/form.ts";
      2 import { AppState } from "#http/routes/_middleware.ts";
      3 import { Handlers, PageProps } from "$fresh/src/server/types.ts";
      4 import { ExceedingLimit } from "#core/domain/limiter.ts";
      5 
      6 type Props = {
      7   scope: string[];
      8   description: string|null;
      9 };
     10 
     11 export const handler: Handlers<Props, AppState<"/connect">> = {
     12   async GET(req, ctx) {
     13     const { oauth2Validate } = ctx.state.app;
     14     const url = new URL(req.url);
     15 
     16     const result = await oauth2Validate.execute({
     17       clientId: String(url.searchParams.get("client_id")),
     18       scope: url.searchParams.has("scope")
     19         ? String(url.searchParams.get("scope"))
     20         : null,
     21     });
     22 
     23     if (!result.valid) {
     24       return ctx.renderNotFound();
     25     }
     26 
     27     return ctx.render({
     28       scope: result.scope,
     29       description: result.description,
     30     });
     31   },
     32 
     33   async POST(req, ctx) {
     34     const { forms, app } = ctx.state;
     35     const { oauth2Initiate } = app;
     36     try {
     37       const url = new URL(req.url);
     38       const clientId = `${url.searchParams.get("client_id")}`;
     39       const result = await oauth2Initiate.execute({
     40         ip: ctx.remoteAddr.hostname,
     41         clientId,
     42         scope: url.searchParams.has("scope")
     43           ? String(url.searchParams.get("scope"))
     44           : null,
     45         state: url.searchParams.has("state")
     46           ? String(url.searchParams.get("state"))
     47           : null,
     48       });
     49 
     50       if  (!result.initiated) {
     51         return ctx.renderNotFound();
     52       }
     53 
     54       const scope = result.scope;
     55       let back = {
     56         form: "/oauth2/callback",
     57         context: { flowId: result.uuid, clientId },
     58       } as Link;
     59 
     60       if (scope.includes("phone-number")) {
     61         back = { form: "/register/phone", context: { back } };
     62       }
     63 
     64       if (scope.includes("id-document")) {
     65         back = {
     66           form: "/register/id-document",
     67           context: { side: "doc-front", back },
     68         };
     69       }
     70 
     71       return forms.redirect({ form: "/connect", context: { back } });
     72     } catch (error) {
     73       if (error instanceof ExceedingLimit) {
     74         throw error;
     75       }
     76       return ctx.renderNotFound();
     77     }
     78   },
     79 };
     80 
     81 const LABELS = {
     82   "phone-number": "Phone number",
     83   "id-document": "ID Document",
     84 } as Record<string, string>;
     85 
     86 export default function AuthorizePage({ data }: PageProps<Props>) {
     87   return (
     88     <article>
     89       <header style="text-align: center;">
     90         <b>Authorize</b>
     91       </header>
     92       <form method="POST">
     93         <p>{data.description}</p>
     94         <ul>
     95           {data.scope.map((scope) => <li>{LABELS[scope] ?? scope}</li>)}
     96         </ul>
     97         <div role="group">
     98           <button type="submit">Consent</button>
     99         </div>
    100       </form>
    101     </article>
    102   );
    103 }