goodmodule / react-facebook

Facebook components like a Login button, Like, Share, Chat, Comments, Page or Embedded Post
MIT License
792 stars 143 forks source link

How do I get app user access token? #210

Open moonman239 opened 1 year ago

moonman239 commented 1 year ago

I have a component defined like so:

import { FacebookProvider, LoginButton} from "react-facebook";
export default function FacebookLoginComponent() {
  const navigate = useNavigate();
  console.log("User entered the Facebook component.");
  return (<div>
    <h1>App</h1>
    <FacebookProvider appId={appId}>
      <LoginButton 
      scope="email"
      onError={(error)=>{
        alert("An error occurred logging into Facebook. Please try again later.")
        console.error(error)
      }}
      onSuccess={(response)=>{
        console.log("user status: " + response.status);
      }}
      >
        Login via Facebook
      </LoginButton>
    </FacebookProvider>
  </div>);
}

Now that the user can log in to Facebook, I want to get their Facebook access token so that I can identify and authenticate them. How do I get the access token?

moonman239 commented 1 year ago

I figured it out this morning.

My solution was to create another login component to use with FacebookProvider:

function LoginComponent()
{
    const {login,status,isLoading,error} = useLogin();
    const handleLogin = async ()=> {
      try {
        const response = await login({scope: "email"});
        localStorage.setItem("fb_access_token",response.authResponse.accessToken);

      }
      catch (e)
      {
        console.error(e);
      }
    }
    return <div>
      {status !== LoginStatus.CONNECTED ? <button onClick={handleLogin}>Login via Facebook</button> : ""}
    </div>
}

So my final source code looks like this:

import * as React from "react";
import { useNavigate } from "react-router";
import { FacebookProvider, LoginButton, LoginStatus, useLogin, useProfile} from "react-facebook";

const appId = "680612673353768";

async function getSubscriptionStatus(accessToken: string) {
  const url = "https://www.hashtagintel.app/flaskapp/customer/subscription_status";
  const fields = "?access_token=" + accessToken;
  const response = await fetch(url + fields);
  const responseJson = await response.json();
  return responseJson["subscription_status"];
}

function LoginComponent()
{
    const {login,status,isLoading,error} = useLogin();
    const handleLogin = async ()=> {
      try {
        const response = await login({scope: "email"});
        localStorage.setItem("fb_access_token",response.authResponse.accessToken);

      }
      catch (e)
      {
        console.error(e);
      }
    }
    return <div>
      {status !== LoginStatus.CONNECTED ? <button onClick={handleLogin}>Login via Facebook</button> : ""}
    </div>
}

export default function FacebookLoginComponent() {
  const navigate = useNavigate();
  console.log("User entered the Facebook component.");
  return (<div>
    <FacebookProvider appId={appId}>
      <LoginComponent></LoginComponent>
    </FacebookProvider>
  </div>);
}
seeden commented 1 year ago

Hi @moonman239. Your solution is correct but I do not understand why first solution is not working for you as well. Did you get response with onSuccess callback ? It is using same logic as you created for you own component

import React, { ReactNode, ComponentType } from 'react';
import useLogin from '../hooks/useLogin';
import type { LoginOptions } from '../hooks/useLogin';
import type { LoginResponse } from '../utils/Facebook';

export type LoginButton = LoginOptions & {
  children?: ReactNode;
  asChild?: ComponentType | keyof JSX.IntrinsicElements;
  disabled?: boolean;
  onError?: (error: Error) => void;
  onSuccess?: (response: LoginResponse) => void;
};

export default function LoginButton(props: LoginButton) {
  const {
    children,
    asChild: AsChild = 'button',
    disabled,
    scope,
    returnScopes,
    authType,
    rerequest,
    reauthorize,
    onError,
    onSuccess,
    ...rest
  } = props;

  const { isLoading, login } = useLogin();

  async function handleLogin() {
    try {
      if (isLoading) {
        return;
      }

      const response = await login({
        scope,
        returnScopes,
        authType,
        rerequest,
        reauthorize,
      });

      onSuccess?.(response);
    } catch (error) {
      onError?.(error as Error);
    }
  }

  return (
    <AsChild
      onClick={handleLogin}
      disabled={isLoading}
      {...rest}
    >
      {children}
    </AsChild>
  );
}