Skip to content

Commit

Permalink
fix(iam): caching access token between github API requests
Browse files Browse the repository at this point in the history
  • Loading branch information
nutrina authored and gdixon committed Sep 7, 2022
1 parent 4e36bca commit 065d9b3
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 42 deletions.
2 changes: 1 addition & 1 deletion iam/src/providers/gitcoinGrantsStatistics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class GitcoinGrantStatisticsProvider implements Provider {
let githubUser: GithubFindMyUserResponse = context.githubUser as GithubFindMyUserResponse;
try {
if (!githubUser) {
githubUser = await verifyGithub(payload.proofs.code);
githubUser = await verifyGithub(payload.proofs.code, context);
context["githubUser"] = githubUser;
}

Expand Down
18 changes: 12 additions & 6 deletions iam/src/providers/github.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ----- Types
import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { ProviderContext, RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { Provider, ProviderOptions } from "../types";
import axios from "axios";

Expand Down Expand Up @@ -27,12 +27,12 @@ export class GithubProvider implements Provider {
}

// verify that the proof object contains valid === "true"
async verify(payload: RequestPayload): Promise<VerifiedPayload> {
async verify(payload: RequestPayload, context: ProviderContext): Promise<VerifiedPayload> {
let valid = false,
verifiedPayload: GithubFindMyUserResponse = {};

try {
verifiedPayload = await verifyGithub(payload.proofs.code);
verifiedPayload = await verifyGithub(payload.proofs.code, context);
} catch (e) {
return { valid: false };
} finally {
Expand All @@ -48,9 +48,14 @@ export class GithubProvider implements Provider {
}
}

export const requestAccessToken = async (code: string): Promise<string> => {
export const requestAccessToken = async (code: string, context: ProviderContext): Promise<string> => {
const clientId = process.env.GITHUB_CLIENT_ID;
const clientSecret = process.env.GITHUB_CLIENT_SECRET;
const accessToken = context.githubAccessToken as string;

if (accessToken) {
return accessToken;
}

// Exchange the code for an access token
const tokenRequest = await axios.post(
Expand All @@ -67,12 +72,13 @@ export const requestAccessToken = async (code: string): Promise<string> => {

const tokenResponse = tokenRequest.data as GithubTokenResponse;

context["githubAccessToken"] = tokenResponse.access_token;
return tokenResponse.access_token;
};

export const verifyGithub = async (code: string): Promise<GithubFindMyUserResponse> => {
export const verifyGithub = async (code: string, context: ProviderContext): Promise<GithubFindMyUserResponse> => {
// retrieve user's auth bearer token to authenticate client
const accessToken = await requestAccessToken(code);
const accessToken = await requestAccessToken(code, context);

// Now that we have an access token fetch the user details
const userRequest = await axios.get("https://api.github.com/user", {
Expand Down
37 changes: 8 additions & 29 deletions iam/src/providers/githubFollowers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// ----- Types
import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { ProviderContext, RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { Provider, ProviderOptions } from "../types";
import { requestAccessToken } from "./github";

// ----- HTTP Client
import axios from "axios";
Expand Down Expand Up @@ -31,12 +32,12 @@ export class TenOrMoreGithubFollowers implements Provider {
}

// verify that the proof object contains valid === "true"
async verify(payload: RequestPayload): Promise<VerifiedPayload> {
async verify(payload: RequestPayload, context: ProviderContext): Promise<VerifiedPayload> {
let valid = false,
verifiedPayload: GithubFindMyUserResponse = {};

try {
verifiedPayload = await verifyGithubFollowerCount(payload.proofs.code);
verifiedPayload = await verifyGithubFollowerCount(payload.proofs.code, context);
} catch (e) {
return { valid: false };
} finally {
Expand Down Expand Up @@ -67,12 +68,12 @@ export class FiftyOrMoreGithubFollowers implements Provider {
}

// verify that the proof object contains valid === "true"
async verify(payload: RequestPayload): Promise<VerifiedPayload> {
async verify(payload: RequestPayload, context: ProviderContext): Promise<VerifiedPayload> {
let valid = false,
verifiedPayload: GithubFindMyUserResponse = {};

try {
verifiedPayload = await verifyGithubFollowerCount(payload.proofs.code);
verifiedPayload = await verifyGithubFollowerCount(payload.proofs.code, context);
} catch (e) {
return { valid: false };
} finally {
Expand All @@ -88,31 +89,9 @@ export class FiftyOrMoreGithubFollowers implements Provider {
}
}

const requestAccessToken = async (code: string): Promise<string> => {
const clientId = process.env.GITHUB_CLIENT_ID;
const clientSecret = process.env.GITHUB_CLIENT_SECRET;

// Exchange the code for an access token
const tokenRequest = await axios.post(
`https://github.com/login/oauth/access_token?client_id=${clientId}&client_secret=${clientSecret}&code=${code}`,
{},
{
headers: { Accept: "application/json" },
}
);

if (tokenRequest.status != 200) {
throw `Post for request returned status code ${tokenRequest.status} instead of the expected 200`;
}

const tokenResponse = tokenRequest.data as GithubTokenResponse;

return tokenResponse.access_token;
};

const verifyGithubFollowerCount = async (code: string): Promise<GithubFindMyUserResponse> => {
const verifyGithubFollowerCount = async (code: string, context: ProviderContext): Promise<GithubFindMyUserResponse> => {
// retrieve user's auth bearer token to authenticate client
const accessToken = await requestAccessToken(code);
const accessToken = await requestAccessToken(code, context);

// Now that we have an access token fetch the user details
const userRequest = await axios.get("https://api.github.com/user", {
Expand Down
6 changes: 3 additions & 3 deletions iam/src/providers/githubForkedRepoProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ----- Types
import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { ProviderContext, RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { Provider, ProviderOptions } from "../types";
import type { GithubFindMyUserResponse, GithubRepoRequestResponse } from "./types/githubTypes";
import { requestAccessToken } from "./github";
Expand All @@ -25,14 +25,14 @@ export class ForkedGithubRepoProvider implements Provider {
}

// verify that the proof object contains valid === "true"
async verify(payload: RequestPayload): Promise<VerifiedPayload> {
async verify(payload: RequestPayload, context: ProviderContext): Promise<VerifiedPayload> {
let valid = false,
accessToken: string,
verifiedUserPayload: GithubFindMyUserResponse = {},
verifiedUserRepoPayload: boolean;

try {
accessToken = await requestAccessToken(payload.proofs.code);
accessToken = await requestAccessToken(payload.proofs.code, context);
verifiedUserPayload = await verifyGithub(accessToken);
verifiedUserRepoPayload = await verifyUserGithubRepo(verifiedUserPayload, accessToken);
valid = verifiedUserPayload && verifiedUserRepoPayload ? true : false;
Expand Down
6 changes: 3 additions & 3 deletions iam/src/providers/githubStarredRepoProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// ----- Types
import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { ProviderContext, RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
import type { Provider, ProviderOptions } from "../types";
import type {
GithubFindMyUserResponse,
Expand Down Expand Up @@ -35,14 +35,14 @@ export class StarredGithubRepoProvider implements Provider {
}

// verify that the proof object contains valid === "true"
async verify(payload: RequestPayload): Promise<VerifiedPayload> {
async verify(payload: RequestPayload, context: ProviderContext): Promise<VerifiedPayload> {
let valid = false,
accessToken: string,
verifiedUserPayload: GithubFindMyUserResponse = {},
verifiedUserRepoPayload: boolean | GithubUserRepoResponseData = {};

try {
accessToken = await requestAccessToken(payload.proofs.code);
accessToken = await requestAccessToken(payload.proofs.code, context);
verifiedUserPayload = await verifyGithub(accessToken);
verifiedUserRepoPayload = await verifyUserGithubRepo(verifiedUserPayload, accessToken);

Expand Down

0 comments on commit 065d9b3

Please sign in to comment.