honojs-middleware/packages/oauth-providers/src/providers/facebook/authFlow.ts

125 lines
3.0 KiB
TypeScript
Raw Normal View History

import { HTTPException } from 'hono/http-exception'
import type { Token } from '../../types'
import { toQueryParams } from '../../utils/objectToQuery'
import type {
FacebookErrorResponse,
FacebookMeResponse,
FacebookTokenResponse,
FacebookUser,
Fields,
Permissions,
} from './types'
type FacebookAuthFlow = {
client_id: string
client_secret: string
redirect_uri: string
scope: Permissions[]
fields: Fields[]
state: string
code: string | undefined
token: Token | undefined
}
export class AuthFlow {
client_id: string
client_secret: string
redirect_uri: string
scope: Permissions[]
fields: Fields[]
state: string
code: string | undefined
token: Token | undefined
user: Partial<FacebookUser> | undefined
constructor({
client_id,
client_secret,
redirect_uri,
scope,
state,
fields,
code,
token,
}: FacebookAuthFlow) {
this.client_id = client_id
this.client_secret = client_secret
this.redirect_uri = redirect_uri
this.scope = scope
this.fields = fields
this.state = state
this.code = code
this.token = token
this.user = undefined
}
redirect() {
const parsedOptions = toQueryParams({
client_id: this.client_id,
redirect_uri: this.redirect_uri,
response_type: ['code', 'granted_scopes'],
scope: this.scope,
state: this.state,
})
return `https://www.facebook.com/v18.0/dialog/oauth?${parsedOptions}`
}
private async getTokenFromCode() {
const parsedOptions = toQueryParams({
client_id: this.client_id,
redirect_uri: this.redirect_uri,
client_secret: this.client_secret,
code: this.code,
})
const url = `https://graph.facebook.com/v18.0/oauth/access_token?${parsedOptions}`
const response = (await fetch(url).then((res) => res.json())) as
| FacebookTokenResponse
| FacebookErrorResponse
if ('error' in response) {
throw new HTTPException(400, { message: response.error?.message })
}
if ('access_token' in response) {
this.token = {
token: response.access_token,
expires_in: response.expires_in,
}
}
}
private async getUserId() {
const response = (await fetch(
`https://graph.facebook.com/v18.0/me?access_token=${this.token?.token}`
).then((res) => res.json())) as FacebookMeResponse | FacebookErrorResponse
if ('error' in response) {
throw new HTTPException(400, { message: response.error?.message })
}
if ('id' in response) {
this.user = response
}
}
async getUserData(): Promise<void> {
await this.getTokenFromCode()
await this.getUserId()
const parsedFields = this.fields.join()
const response = (await fetch(
`https://graph.facebook.com/${this.user?.id}?fields=${parsedFields}&access_token=${this.token?.token}`
).then((res) => res.json())) as FacebookUser | FacebookErrorResponse
if ('error' in response) {
throw new HTTPException(400, { message: response.error?.message })
}
if ('id' in response) {
this.user = response
}
}
}