@localsecurity/cf-access-service
Version:
A utility to parse Cloudflare Access user identity inside Cloudflare Workers
129 lines (124 loc) • 5.17 kB
text/typescript
/**
* This User Identity object is returned from https://\<your-team-name\>.cloudflareaccess.com/cdn-cgi/access/get-identity
*/
type CFAccessUserIdentity = {
/** The IP address of the user. */
ip: string;
/** Data from your identity provider. */
idp: string;
/** The country where the user authenticated from. */
geo: string;
/** The timestamp indicating when the user logged in. */
iat: number;
/** The email address of the user. */
email: string;
/** True if the user enabled WARP. */
is_warp: boolean;
/** The version of the get-identity object. */
version: string;
/** The ID of the user. */
user_uuid: string;
/** The ID of the device used for authentication. */
device_id: string;
/** The account ID for your organization. */
account_id: string;
/** True if the user enabled WARP and authenticated to a Zero Trust team. */
is_gateway: boolean;
/** The status if authenticating with mTLS. */
auth_status: string;
/** The common name on the mTLS client certificate. */
common_name: string;
/** The device posture attributes. */
devicePosture: string;
/** A list of all sessions initiated by the user. */
device_sessions: object;
/** The Client ID of the service token used for authentication. */
service_token_id: string;
/** An ID generated by the WARP client when authenticated to a Zero Trust team. */
gateway_account_id: string;
/** True if authentication was through a service token instead of an IdP. */
service_token_status: string;
};
/**
* Parsed CF_Authorization (cookie and header) token
*/
type CFAccessUserToken = {
/** Application audience (AUD) tag of the Access application. */
aud: string;
/** The expiration timestamp for the token (Unix time). */
exp: number;
/** The issuance timestamp for the token (Unix time). */
iat: number;
/** The not-before timestamp for the token (Unix time), used to check if the token was received before it should be used. */
nbf: number;
/** The Cloudflare Access domain URL for the application. */
iss: string;
/** The ID of the user. This value is unique to an email address per account. The user would get a different sub if they are removed and re-added to your Zero Trust organization, or if they log into a different organization. */
sub: string;
/** The type of Access token (app for application token or org for global session token). */
type: string;
/** The email address of the authenticated user, verified by the identity provider. */
email: string;
/** The country where the user authenticated from. */
country: string;
/** A cache key used to get the user's identity. */
identity_nonce: string;
};
/**
* A class to validate incomming requests
* @method getIdentity - Returns a parsed CFAccessUserIdentity object if the user is logged in
* @method getEmail - Returns the users Email if the user is logged in
*/
class CFAccessService {
/**
* Returns a parsed CFAccessUserIdentity object if the user is logged in
* @param {Request} request - the incomming request to validate
* @param {Env} env - environment object
* @returns {Partial<CFAccessUserIdentity>} The users identity
*/
async getIdentity(request: Request | any, env: any): Promise<Partial<CFAccessUserIdentity>> {
const formatID = (data: any) => {
let N = (d: any, k: string) => T(d[k], 'number');
let S = (d: any, k: string) => T(d[k], 'string');
let B = (d: any, k: string) => T(d[k], 'boolean');
let T = (i: any, t: string) => (typeof i === t ? i : void 0);
return {
id: S(data, 'id') as string | undefined,
ip: S(data, 'ip') as string | undefined,
idp: S(data, 'idp') as string | undefined,
iat: N(data, 'iat') as number | undefined,
name: S(data, 'name') as string | undefined,
email: S(data, 'email') as string | undefined,
is_warp: B(data, 'is_warp') as boolean | undefined,
is_gateway: B(data, 'is_gateway') as boolean | undefined,
auth_status: S(data, 'auth_status') as string | undefined,
service_token_id: S(data, 'service_token_id') as string | undefined,
service_token_status: B(data, 'service_token_status') as string | undefined,
};
};
let id;
const team = env['WORKSPACE'] ? env['WORKSPACE'] : 'example-ls';
const suffix = 'cloudflareaccess.com/cdn-cgi/access/get-identity';
const url = new URL(`https://${team}.${suffix}`);
const resp = await fetch(url, request.clone());
const data = await resp.json();
if (data) id = formatID(data);
else id = { email: '' };
return id;
}
/**
* Returns the users Email if the user is logged in
* @param {Request} request - the incomming request to validate
* @param {Env} env - environment object
* @returns The users email or null
*/
async getEmail(request: Request | any, env: any): Promise<string | null> {
const id = await this.getIdentity(request, env);
const email = id['email'];
if (email) return email;
return null;
}
}
export { CFAccessService };
export type { CFAccessUserIdentity, CFAccessUserToken };
export default CFAccessService;