universal_authentication
Version:
Seamless and Secure Authentication for Modern Web Applications: Easily integrate OTP-based email verification, Google OAuth, GitHub, Microsoft, and Okta login into your Node.js app. Modular, flexible, and database-agnostic, this package simplifies user au
149 lines (138 loc) • 5.04 kB
text/typescript
import axios from "axios";
import { IOAuthConfig } from "../interface/OAuth.interface";
// function to genrate OAuth url
export const initiateLogin = (
provider: "google" | "github" | "microsoft" | "okta",
clientId: string,
redirectUri: string
): string => {
const providerUrls = {
google: `https://accounts.google.com/o/oauth2/v2/auth?client_id=${clientId}&redirect_uri=${redirectUri}&response_type=code&scope=profile email`,
github: `https://github.com/login/oauth/authorize?client_id=${clientId}`,
microsoft: `https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}&response_mode=query&scope=https://graph.microsoft.com/.default`,
okta: `${process.env.OKTA_DOMAIN}/v1/authorize?client_id=${clientId}&response_type=code&scope=openid profile email&redirect_uri=${redirectUri}`,
};
return providerUrls[provider];
};
//function to handle OAuth callback
export const handleOAuthCallback = async (
code: string,
provider: "google" | "github" | "microsoft" | "okta",
config: IOAuthConfig
): Promise<any> => {
try {
if (!code) {
return { status: 400, message: "Authorization code is missing" };
}
// token urls of particular provider and their payloads
const tokenUrls = {
google: "https://oauth2.googleapis.com/token",
github: "https://github.com/login/oauth/access_token",
microsoft: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
okta: `${process.env.OKTA_DOMAIN}/oauth/token`,
};
const tokenPayloads =
provider === "google"
? {
code,
client_id: config.clientId,
client_secret: config.clientSecret,
redirect_uri: config.redirectUri,
grant_type: "authorization_code",
}
: provider === "github"
? {
client_id: config.clientId,
client_secret: config.clientSecret,
code,
}
: provider === "microsoft"
? {
client_id: config.clientId,
client_secret: config.clientSecret,
code,
redirect_uri: config.redirectUri,
grant_type: "authorization_code",
}
: {
grant_type: "authorization_code",
code,
redirect_uri: config.redirectUri,
client_id: config.clientId,
client_secret: config.clientSecret,
};
// Microsoft-specific header for token exchange
const tokenHeaders =
provider === "microsoft"
? { "Content-Type": "application/x-www-form-urlencoded" }
: { Accept: "application/json" };
//Exchange authorization code for access token
const { data: tokenData } = await axios.post(
tokenUrls[provider],
tokenPayloads,
{
headers: tokenHeaders,
}
);
const accessToken = tokenData.access_token;
if (!accessToken) {
return { status: 400, message: "Failed to get access token" };
}
//user profile url to fetch the particular user
const userinfoUrls = {
google: "https://www.googleapis.com/oauth2/v1/userinfo",
github: "https://api.github.com/user",
microsoft: "https://graph.microsoft.com/v1.0/me",
okta: `${process.env.OKTA_DOMAIN}/v1/userinfo`,
};
//fetch user profile from OAuth provider
const { data: profileData } = await axios.get(userinfoUrls[provider], {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
// extract relevant user details
const userData =
provider === "google"
? {
providerId: profileData.id,
name: profileData.name,
email: profileData.email,
provider,
}
: provider === "github"
? {
providerId: profileData.id,
username: profileData.login,
name: profileData.name,
provider,
}
: provider === "microsoft"
? {
providerId: profileData.id,
name: profileData.displayName,
email: profileData.mail || profileData.userPrincipalName,
provider,
}
: {
providerId: profileData.sub,
name: profileData.name,
email: profileData.email,
provider,
};
//check if the user exist
const existingUser = await config.findUserById(userData.providerId);
if (!existingUser) {
const newUser = await config.createUser(userData);
return {
status: 200,
message: "User created successfully",
user: newUser,
};
} else {
return { status: 200, message: "User already exist", user: existingUser };
}
} catch (err) {
return { status: 500, message: `Failed to get loged in to ${provider}` };
}
};