Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | 1x 2x 2x 2x 2x 2x 5x 5x 5x 1x 4x 4x 4x 4x 4x 4x 5x 5x 5x 5x 5x 5x 14x 14x | import { HttpService, Inject, Injectable } from "@nestjs/common";
import { AxiosError } from "axios";
import { THIRD_PARTY_OPTIONS_PROVIDER } from "./constants";
import { ConfigDetail, FacebookDebugTokenInfo, FacebookUserInfo, IThirdPartyAuthPluginOptions } from "./interfaces";
import path from 'path'
@Injectable()
export class FacebookAuthService {
private endpoint: string = 'https://graph.facebook.com'
private version: string = 'v16.0'
private optionDetail: ConfigDetail
constructor(
@Inject(HttpService) private httpService: HttpService,
@Inject(THIRD_PARTY_OPTIONS_PROVIDER) private options: Required<IThirdPartyAuthPluginOptions>
) {
this.optionDetail = options.facebook
}
/**
* The flow to verify a token will be:
*
* 1. Generate app_token using client_id, and client_secret
* 2. Inspect the token below using app_token
* 3. Call /me endpoint on behalf of user to get user's email
*
* @param token the token is retrieved from Facebook dialog in front-end
*/
async verify(token: string) {
const appToken = await this.generateAppToken()
const tokenDebugInfo = await this.inspectToken(token, appToken)
if (!tokenDebugInfo.is_valid) {
throw new Error('Token is invalid')
}
Iif (!tokenDebugInfo.scopes.includes('email')) {
throw new Error('User not grant "email" permission')
}
const userInfo = await this.getUserInfo(token)
return userInfo
}
private async getUserInfo(token: string): Promise<FacebookUserInfo> {
const url = this.constructUrl('me')
const res = await this.httpService.get<FacebookUserInfo>(url, {
params: {
fields: ['id', 'email', 'first_name', 'last_name'].join(),
},
headers: {
"Authorization": `Bearer ${token}`
}
}).toPromise()
return res.data
}
private async inspectToken(token: string, appToken: string): Promise<FacebookDebugTokenInfo> {
const url = this.constructUrl('debug_token', false)
const res = await this.httpService.get<{data: FacebookDebugTokenInfo}>(url, { params: {
input_token: token,
access_token: appToken
} }).toPromise()
return res.data.data
}
private async generateAppToken(): Promise<string> {
const url = this.constructUrl('oauth/access_token', false)
const res = await this.httpService.get<{access_token: string}>(url, { params: {
client_id: this.optionDetail.clientId,
client_secret: this.optionDetail.clientSecret,
grant_type: 'client_credentials'
}}).toPromise()
return res.data.access_token
}
private constructUrl(edge: string, withVersion: boolean = true) {
const url = path.join(this.endpoint, withVersion ? this.version : '', edge)
return url.toString()
}
} |