I'm trying to set up the Facebook authentication strategy on my app using Passport.js, Express and TypeScript. I could understand the dataflow of the process thanks to this article from Hacker Noon.
But when it comes to the verification callback function, things get a little troublesome. I need to check whether the user is already logged in, thus the access to the Request object is necessary. I've checked in the passport-facebook
module docs that passReqToCallback: true
can be set on the strategy options to enable this.
However when I pass the req
parameter to the callback function, the compiler throws the following error:
Argument of type '(req: Request, accessToken: string, _refreshToken: string, profile: Profile, done: any) => void' is not assignable to parameter of type 'VerifyFunction'.
Looking around the type definitions of the Passport.js module I found this:
export type VerifyFunction =
(accessToken: string, refreshToken: string, profile: Profile, done: (error: any, user?: any, info?: any) => void) => void;
export type VerifyFunctionWithRequest =
(req: express.Request, accessToken: string, refreshToken: string, profile: Profile, done: (error: any, user?: any, info?: any) => void) => void;
export class Strategy implements passport.Strategy {
constructor(options: StrategyOptionWithRequest, verify: VerifyFunctionWithRequest);
constructor(options: StrategyOption, verify: VerifyFunction);
name: string;
authenticate(req: express.Request, options?: object): void;
}
So, in theory, the declaration
new Strategy(fbConfig, (req: Request, accessToken: string, _refreshToken: string, profile: Profile, done: any) => { ... });
should be accepted with no problems.
Here is the full fbConfig
declaration:
const fbConfig = {
clientID: "",
clientSecret: "",
callbackURL: "",
passReqToCallback: true,
profileFields: [
"id",
"name",
"birhday",
"gender",
"email",
"location",
"hometown"
]
};
And my tsconfig.json
:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"strict": true,
"noImplicitAny": true,
"esModuleInterop": true,
"baseUrl": ".",
"outDir": "dist",
"paths": {
"@models/*": ["./src/models/*"],
"@configs/*": ["./src/configs/*"],
"@controllers/*": ["./src/controllers/*"]
}
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
If anyone could help me out with this, I'd appreciate it pretty much!
I've tried what Shanon Jackson recommended, but it didn't work. The compiler couldn't recognize the overloaded constructor for the Strategy
class.
So what I did was:
new Strategy(
fbConfig as StrategyOptionWithRequest,
(
req: Request,
accessToken: string,
_refreshToken: string,
profile: Profile,
done
) => { ... }
);
I suppose that casting the fbConfig
object to StrategyOptionWithRequest
forced the compiler to use the constructor that expected that interface. Then I annotated the types of the callback function parameters, but left done
to the compiler inference system to deal with. Annotating it to any
seemed to mess a bit with VSCode's IntelliSense system, making it do not display done
's expected parameters.