From d04986b75b31b249a66058fad70ca8d199f3d6ad Mon Sep 17 00:00:00 2001 From: pilcrowOnPaper <80624252+pilcrowOnPaper@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:59:37 +0900 Subject: [PATCH] Add Box OAuth provider (#1016) --- .auri/$6qq2nr4z.md | 6 ++ packages/oauth/src/providers/box.ts | 150 ++++++++++++++++++++++++++ packages/oauth/src/providers/index.ts | 3 + 3 files changed, 159 insertions(+) create mode 100644 .auri/$6qq2nr4z.md create mode 100644 packages/oauth/src/providers/box.ts diff --git a/.auri/$6qq2nr4z.md b/.auri/$6qq2nr4z.md new file mode 100644 index 000000000..5e500f495 --- /dev/null +++ b/.auri/$6qq2nr4z.md @@ -0,0 +1,6 @@ +--- +package: "@lucia-auth/oauth" # package name +type: "minor" # "major", "minor", "patch" +--- + +Add Box provider \ No newline at end of file diff --git a/packages/oauth/src/providers/box.ts b/packages/oauth/src/providers/box.ts new file mode 100644 index 000000000..670be1cb6 --- /dev/null +++ b/packages/oauth/src/providers/box.ts @@ -0,0 +1,150 @@ +import { + OAuth2ProviderAuth, + createOAuth2AuthorizationUrl, + validateOAuth2AuthorizationCode +} from "../core/oauth2.js"; +import { ProviderUserAuth } from "../core/provider.js"; +import { handleRequest, authorizationHeader } from "../utils/request.js"; + +import type { Auth } from "lucia"; + +type Config = { + clientId: string; + clientSecret: string; + redirectUri: string; +}; + +const PROVIDER_ID = "box"; + +export const box = <_Auth extends Auth = Auth>( + auth: _Auth, + config: Config +): BoxAuth<_Auth> => { + return new BoxAuth(auth, config); +}; + +export class BoxAuth<_Auth extends Auth = Auth> extends OAuth2ProviderAuth< + BoxUserAuth<_Auth> +> { + private config: Config; + + constructor(auth: _Auth, config: Config) { + super(auth); + + this.config = config; + } + + public getAuthorizationUrl = async (): Promise< + readonly [url: URL, state: string] + > => { + return await createOAuth2AuthorizationUrl( + "https://account.box.com/api/oauth2/authorize", + { + clientId: this.config.clientId, + redirectUri: this.config.redirectUri, + scope: [] + } + ); + }; + + public validateCallback = async ( + code: string + ): Promise> => { + const boxTokens = await this.validateAuthorizationCode(code); + const boxUser = await getBoxUser(boxTokens.accessToken); + return new BoxUserAuth(this.auth, boxUser, boxTokens); + }; + + private validateAuthorizationCode = async ( + code: string + ): Promise => { + const tokens = await validateOAuth2AuthorizationCode<{ + access_token: string; + }>(code, "https://api.box.com/oauth2/token", { + clientId: this.config.clientId, + redirectUri: this.config.redirectUri, + clientPassword: { + authenticateWith: "client_secret", + clientSecret: this.config.clientSecret + } + }); + return { + accessToken: tokens.access_token + }; + }; +} + +export class BoxUserAuth< + _Auth extends Auth = Auth +> extends ProviderUserAuth<_Auth> { + public boxTokens: BoxTokens; + public boxUser: BoxUser; + + constructor(auth: _Auth, boxUser: BoxUser, boxTokens: BoxTokens) { + super(auth, PROVIDER_ID, boxUser.id.toString()); + + this.boxTokens = boxTokens; + this.boxUser = boxUser; + } +} + +const getBoxUser = async (accessToken: string): Promise => { + const request = new Request("https://api.box.com/2.0/users/me", { + headers: { + Authorization: authorizationHeader("bearer", accessToken) + } + }); + const boxUser = await handleRequest(request); + return boxUser; +}; + +export type BoxTokens = { + accessToken: string; +}; + +export type BoxUser = { + id: string; + type: "user"; + address: string; + avatar_url: string; + can_see_managed_users: boolean; + created_at: string; + enterprise: { + id: string; + type: string; + name: string; + }; + external_app_user_id: string; + hostname: string; + is_exempt_from_device_limits: boolean; + is_exempt_from_login_verification: boolean; + is_external_collab_restricted: boolean; + is_platform_access_only: boolean; + is_sync_enabled: boolean; + job_title: string; + language: string; + login: string; + max_upload_size: number; + modified_at: string; + my_tags: [string]; + name: string; + notification_email: { + email: string; + is_confirmed: boolean; + }; + phone: string; + role: string; + space_amount: number; + space_used: number; + status: + | "active" + | "inactive" + | "cannot_delete_edit" + | "cannot_delete_edit_upload"; + timezone: string; + tracking_codes: { + type: string; + name: string; + value: string; + }[]; +}; diff --git a/packages/oauth/src/providers/index.ts b/packages/oauth/src/providers/index.ts index 1816fa615..e7e94bcaf 100644 --- a/packages/oauth/src/providers/index.ts +++ b/packages/oauth/src/providers/index.ts @@ -30,6 +30,9 @@ export type { AzureADUserAuth } from "./azure-ad.js"; +export { box } from "./box.js"; +export type { BoxAuth, BoxTokens, BoxUser, BoxUserAuth } from "./box.js"; + export { discord } from "./discord.js"; export type { DiscordAuth,