#Can't get @deno/kv-oauth to work

5 messages · Page 1 of 1 (latest)

lapis pebble
#

Hello, I am trying to use @deno/kv-oauth to enable login only for myself. I am using Angular in the frontend and Deno Deploy here. I would like to use Github OAuth for this and have already created an OAuth app—that should be fine. However, in my Angular frontend, I always get the following response:

https://secret.deno.dev/protected-route
401 Unauthorized

I haven't been able to get the whole thing to run locally yet, which makes it even more difficult. I would first show my Deno code here and then what I have in Angular. Maybe someone has an idea.

#
import { createGitHubOAuthConfig, createHelpers } from 'jsr:@deno/kv-oauth';
import { STATUS_CODE, StatusCode } from 'jsr:@std/http/status';
import { oauthCallback } from './handler/oauth-callback.ts';
import { getSession } from './utils/db.ts'; 

export const ALLOWED_USER = Deno.env.get('ALLOWED_GITHUB_USER');
const OAUTH_REDIRECT_URI = Deno.env.get('OAUTH_REDIRECT_URI');

if (!ALLOWED_USER) {
  console.error('🚨 ALLOWED_GITHUB_USER not set!');
}

if (!OAUTH_REDIRECT_URI) {
  console.error('🚨 OAUTH_REDIRECT_URI not set!');
}

export const oauthConfig = createGitHubOAuthConfig({
  redirectUri: OAUTH_REDIRECT_URI,
});

export const {
  signIn,
  getSessionId,
  signOut,
  handleCallback,
} = createHelpers(oauthConfig);

const withCorsHeaders = (
  message: string,
  status: StatusCode = 200,
): Response => {
  const body = JSON.stringify({ message });
  const headers = new Headers();
  headers.set('Content-Type', 'application/json');
  headers.set('Access-Control-Allow-Origin', 'https://telesto.github.io');
  headers.set('Access-Control-Allow-Credentials', 'true');
  headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
  headers.set('Access-Control-Allow-Headers', 'Content-Type');

  return new Response(body, {
    status,
    headers,
  });
};
#
const handler = async (request: Request): Promise<Response> => {
  if (request.method === 'OPTIONS') {
    return new Response(null, {
      headers: {
        'Access-Control-Allow-Origin': 'https://tonyspegel.github.io',
        'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
        'Access-Control-Allow-Headers': 'Content-Type, Authorization',
        'Access-Control-Allow-Credentials': 'true',
      },
    });
  }

  const { pathname } = new URL(request.url);

  switch (pathname) {
    case '/oauth/signin':
      return await signIn(request);

    case '/oauth/callback':
      return await oauthCallback(request);

    case '/oauth/signout':
      return await signOut(request);

    case '/protected-route': {
      const sessionId = await getSessionId(request);
      if (!sessionId) {
        return withCorsHeaders(
          'Unauthenticated request',
          STATUS_CODE.Unauthorized,
        );
      }

      const user = await getSession(sessionId);

      if (!user) {
        return withCorsHeaders(
          'No valid session found',
          STATUS_CODE.Unauthorized,
        );
      }

      return withCorsHeaders(
        `Authenticated as ${user.login}`,
        STATUS_CODE.OK,
      );
    }

    default:
      return withCorsHeaders('Route not found', STATUS_CODE.NotFound);
  }
};

Deno.serve(handler);
#

then the callback:

import { STATUS_CODE } from 'jsr:@std/[email protected]/status';
import { ALLOWED_USER, handleCallback } from '../main.ts';
import { setSession } from '../utils/db.ts';

export const oauthCallback = async (request: Request): Promise<Response> => {
  const { sessionId, tokens } = await handleCallback(request);
  const githubUserRes = await fetch('https://api.github.com/user', {
    headers: {
      Authorization: `bearer ${tokens.accessToken}`,
      'User-Agent': 'scan-lab-login',
    },
  });

  const githubUser = await githubUserRes.json();
  if (githubUser.login !== ALLOWED_USER) {
    return new Response('Unauthorized', {
      status: STATUS_CODE.Unauthorized,
    });
  }

  await setSession(sessionId, { login: githubUser.login });

  return Response.redirect(
    'https://telesto.github.io/sla-admin',
    STATUS_CODE.TemporaryRedirect,
  );
};
#

and kv utility

export const kv = await Deno.openKv();

export interface SessionUser {
  login: string;
}

export const setSession = async (
  sessionId: string,
  user: SessionUser,
): Promise<void> => {
  await kv.set(['oauth_user', sessionId], user);
};

export const getSession = async (
  sessionId: string,
): Promise<SessionUser | null> => {
  const entry = await kv.get<SessionUser>(['oauth_user', sessionId]);
  return entry.value ?? null;
};

export const deleteSession = async (sessionId: string): Promise<void> => {
  await kv.delete(['oauth_user', sessionId]);
};