@adonisjs/ally
Version:
Social authentication provider for AdonisJS
233 lines (231 loc) • 6.21 kB
JavaScript
import {
Oauth2Driver
} from "../../chunk-EXGR73T6.js";
import "../../chunk-NK6X76EQ.js";
import "../../chunk-TSIMPJ6I.js";
// src/drivers/google.ts
var SCOPE_PREFIXES = {
"https://www.googleapis.com/auth": [
"userinfo.email",
"userinfo.profile",
"contacts",
"contacts.other.readonly",
"contacts.readonly",
"directory.readonly",
"user.addresses.read",
"user.birthday.read",
"user.emails.read",
"user.gender.read",
"user.organization.read",
"user.phonenumbers.read",
"analytics",
"analytics.readonly",
"documents",
"documents.readonly",
"forms",
"forms.currentonly",
"groups",
"spreadsheets",
"calendar",
"calendar.events",
"calendar.events.readonly",
"calendar.readonly",
"calendar.settings.readonly",
"drive",
"drive.appdata",
"drive.file",
"drive.metadata",
"drive.metadata.readonly",
"drive.photos.readonly",
"drive.readonly",
"drive.scripts"
]
};
var GoogleDriver = class extends Oauth2Driver {
/**
* @param ctx - The HTTP context
* @param config - Configuration for the Google driver
*/
constructor(ctx, config) {
super(ctx, config);
this.config = config;
this.loadState();
}
config;
/**
* Google token endpoint URL.
*/
accessTokenUrl = "https://oauth2.googleapis.com/token";
/**
* Google authorization endpoint URL.
*/
authorizeUrl = "https://accounts.google.com/o/oauth2/v2/auth";
/**
* Google user profile endpoint URL.
*/
userInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo";
/**
* The param name for the authorization code
*/
codeParamName = "code";
/**
* The param name for the error
*/
errorParamName = "error";
/**
* Cookie name for storing the "google_oauth_state"
*/
stateCookieName = "google_oauth_state";
/**
* Parameter name to be used for sending and receiving the state
* from google
*/
stateParamName = "state";
/**
* Parameter name for defining the scopes
*/
scopeParamName = "scope";
/**
* Scopes separator
*/
scopesSeparator = " ";
/**
* Configures the redirect request with default scopes and Google-specific
* parameters like access_type, prompt, display, and hosted domain.
*
* @param request - The redirect request to configure
*/
configureRedirectRequest(request) {
request.transformScopes((scopes) => this.buildScopes(scopes));
request.scopes(this.config.scopes || ["openid", "userinfo.email", "userinfo.profile"]);
request.param("response_type", "code");
if (this.config.accessType) {
request.param("access_type", this.config.accessType);
}
if (this.config.prompt) {
request.param("prompt", this.config.prompt);
}
if (this.config.display) {
request.param("display", this.config.display);
}
if (this.config.hostedDomain) {
request.param("hd", this.config.hostedDomain);
}
}
/**
* Creates an authenticated HTTP request with the proper authorization
* header for Google API calls.
*
* @param url - The API endpoint URL
* @param token - The access token
*/
getAuthenticatedRequest(url, token) {
const request = this.httpClient(url);
request.header("Authorization", `Bearer ${token}`);
request.header("Accept", "application/json");
request.parseAs("json");
return request;
}
/**
* Fetches the authenticated user's profile information from the Google API.
*
* @param token - The access token
* @param callback - Optional callback to customize the API request
*/
async getUserInfo(token, callback) {
const request = this.getAuthenticatedRequest(this.config.userInfoUrl || this.userInfoUrl, token);
if (typeof callback === "function") {
callback(request);
}
const body = await request.get();
return {
id: body.sub,
nickName: body.name,
name: body.name,
email: body.email,
avatarUrl: body.picture,
emailVerificationState: body.email_verified ? "verified" : "unverified",
original: body
};
}
/**
* Check if the error from the callback indicates that the user
* denied authorization.
*/
accessDenied() {
const error = this.getError();
if (!error) {
return false;
}
return error === "access_denied";
}
/**
* Get the access token using the authorization code from the callback request.
* Returns a GoogleToken that includes the ID token.
*
* @param callback - Optional callback to customize the API request
*/
async accessToken(callback) {
const token = await super.accessToken(callback);
return {
...token,
idToken: token.id_token
};
}
/**
* Get the authenticated user's profile information using
* the authorization code from the callback request.
*
* @param callback - Optional callback to customize the API request
*
* @example
* ```ts
* const user = await ally.use('google').user()
* console.log(user.name, user.email)
* ```
*/
async user(callback) {
const token = await this.accessToken(callback);
const user = await this.getUserInfo(token.token, callback);
return {
...user,
token
};
}
/**
* Get the user's profile information using an existing
* access token.
*
* @param token - The Google access token
* @param callback - Optional callback to customize the API request
*
* @example
* ```ts
* const user = await ally.use('google').userFromToken(accessToken)
* ```
*/
async userFromToken(token, callback) {
const user = await this.getUserInfo(token, callback);
return {
...user,
token: { token, type: "bearer" }
};
}
/**
* Prefixes Google scopes with the appropriate API URL.
* Converts short scope names like 'userinfo.email' to full URLs.
*
* @param scopes - Array of scope names to prefix
*/
buildScopes(scopes) {
return scopes.map((name) => {
const prefix = Object.keys(SCOPE_PREFIXES).find(
(one) => SCOPE_PREFIXES[one].includes(name)
);
return prefix ? `${prefix}/${name}` : name;
});
}
};
export {
GoogleDriver
};