declare module 'passport-oauth2' {
    import { Request } from 'express';
    import { Strategy } from 'passport';
    import { OAuth2 } from 'oauth';
    import { OutgoingHttpHeaders } from 'http';

    class OAuth2Strategy extends Strategy {
        name: string;
        protected _oauth2: OAuth2;

        constructor(options: OAuth2Strategy._StrategyOptionsBase, verify: OAuth2Strategy.VerifyFunction | OAuth2Strategy.VerifyFunctionWithRequest);

        authenticate(req: Request, options?: any): void;

        userProfile(accessToken: string, done: (err?: Error | null, profile?: any) => void): Promise<void>;
        authorizationParams(options: any): object;
        tokenParams(options: any): object;
        parseErrorResponse(body: any, status: number): Error | null;
    }

    namespace OAuth2Strategy {
        interface Metadata {
            authorizationURL: string;
            tokenURL: string;
            clientID: string;
        }

        type StateStoreStoreCallback = (err: Error | null, state: any) => void;
        type StateStoreVerifyCallback = (err: Error, ok: boolean, state: any) => void;

        interface StateStore {
            store(req: Request, callback: StateStoreStoreCallback): void;
            store(req: Request, meta: Metadata, callback: StateStoreStoreCallback): void;

            verify(req: Request, state: string, callback: StateStoreVerifyCallback): void;
            verify(req: Request, state: string, meta: Metadata, callback: StateStoreVerifyCallback): void;
        }

        type VerifyCallback = (err?: Error | null, user?: object, info?: object) => void;

        export type VerifyFunction =
            ((accessToken: string, refreshToken: string, profile: any, verified: VerifyCallback) => void) |
            ((accessToken: string, refreshToken: string, results: any, profile: any, verified: VerifyCallback) => void);
        export type VerifyFunctionWithRequest =
            ((req: Request, accessToken: string, refreshToken: string, profile: any, verified: VerifyCallback) => void) |
            ((req: Request, accessToken: string, refreshToken: string, results: any, profile: any, verified: VerifyCallback) => void);

        export interface _StrategyOptionsBase {
            authorizationURL: string;
            tokenURL: string;
            clientID: string;
            clientSecret: string;
            callbackURL?: string;
            customHeaders?: OutgoingHttpHeaders;
            scope?: string | string[];
            scopeSeparator?: string;
            sessionKey?: string;
            store?: StateStore;
            state?: any;
            skipUserProfile?: any;
            pkce?: boolean;
            proxy?: any;
            passReqToCallback?: boolean;
        }

        type Strategy = OAuth2Strategy;
        const Strategy: typeof OAuth2Strategy;

        class TokenError extends Error {
            constructor(message: string | undefined, code: string, uri?: string, status?: number);
            code: string;
            uri?: string;
            status: number;
        }

        class AuthorizationError extends Error {
            constructor(message: string | undefined, code: string, uri?: string, status?: number);
            code: string;
            uri?: string;
            status: number;
        }

        class InternalOAuthError extends Error {
            constructor(message: string, err: any);
            oauthError: any;
        }
    }
    export = OAuth2Strategy;
}

