UNPKG

@localsecurity/cf-access-service

Version:

A utility to parse Cloudflare Access user identity inside Cloudflare Workers

129 lines (124 loc) 5.17 kB
/** * 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;