react-implicit-auth

React Implicit Authorization

npmbundlephobiaContributionsLicenseexamples

React Implicit Authorization is a React Provider component that simplifies the implicit grant flow authorization and authentication process using the following social API providers:

Technically it's a wrapper on top of the SDK interface delivered by social providers.

Read docs for more details.

docs build netlify

Install

$ npm install react-implicit-auth
$ yarn add react-implicit-auth

Motivation

The main idea is to unify the social provides API interface and solve the following problems:

  • A different methods naming, API usage, responses. The component tries to solve issue unifying stuff
  • A complex documentation. Using the component you save time for testing and reading docs
  • A lack of auto initialization. The component allows you to append SDK scripts and initialize them based on the configuration you provide

Docs

See the documentation for more information about using react-implicit-auth package.

Troubleshooting

After running yarn start browser complains that "your connection is not secure"?

Ignore it and add an exception for this page. The page should have https to make because most of the providers require it.

Google login doesn't work in incognito mode?

This is one of the limitations of the implicit grant flow. Google login might not work in incognito mode or when third-party cookies are blocked: issue.

Contributing

If you want to contribute to react-implicit-auth please see the contributing guideline.

import { ImplicitAuthProvider } from 'react-implicit-auth';

A React Context Provider component that passes into its context unified social API methods and simplifies SDK initialization routine.

Prop nameTypeDefaultDescription
configConfigRequired
autoInitbooleantrue

Allows to load and initialize SDK scripts automatically based on config.

autoLoginbooleantrue

Gets the login status authenticating a user. If a token expired or a user has not been authenticated at all the error throws. To listen to the error use pass callback to onAutoLoginSuccess prop. Normally, after the page reload a user have to click the login button again. Having the prop enabled let authentication happens automatically. To keep it works don't set false to autoInit and autoLogin props.

onAutoLoginError(error?: any) => voidnull

Gets called on login error if autoLogin enabled. To keep it works don't set false to autoInit and autoLogin props.

onAutoLoginSuccess(auth?: any) => voidnull

Gets called on login error if autoLogin enabled To keep it works don't set false to autoInit and autoLogin props.

onInitError(error?: any) => voidnull

Gets called on SDK init error if autoInit enabled.

onInitSuccess(error?: any) => voidnull

Gets called on SDK init success if autoInit enabled.

<ImplicitAuthProvider /> is a component that registers, loads, and creates unify social SDK methods. At the moment it handles the following SDK:

Put <ImplicitAuthProvider /> somewhere high in your app, above components that might use its API:

import { ImplicitAuthProvider } from 'react-implicit-auth';
import MyPage from './MyPage'

const handleAuthProviderError = (error) => {
  console.error(error);
}
const handleAuthProviderSuccess = (data) => {
  console.log(data);
}

const MyApp = () => (
  <ImplicitAuthProvider
    onInitError={handleAuthProviderError}
    onAutoLoginError={handleAuthProviderError}
    onAutoLoginSuccess={handleAuthProviderSuccess}
    onInitSuccess={handleAuthProviderSuccess}
    config={{
      facebook: {
        debug: true,
        appId: '****************',
        cookie: true,
        version: 'v9.0',
        xfbml: false,
      },
      google: {
        clientId: '*****.apps.googleusercontent.com',
        scope: 'profile email',
      },
    }}
  >
    <MyPage />
  </ImplicitAuthProvider>
);

export default MyApp;

On this page, you can find how to use and test context methods passed by ImplicitAuthProvider using React Context.

Prop nameTypeDefaultDescription
api(args?: ApiRequestOptions) => Promise<MethodResult<any>>Required

Allows to make requests to provider API.

autoLogin() => Promise<MethodResult<AuthData>>Required

Gets login status on page init and allows to authenticate users automatically if a token has not been expired.

getUserProfile() => Promise<MethodResult<UserProfile>>Required

Retrieves authenticated user profile.

grant({ scope }: { scope: string; }) => Promise<MethodResult<AuthData>>Required

Extends authorization scope. The difference between login() and grant() is that the first one uses the scope defined in Config object. Using this method it's possible to set different scope then defined in the initial config.

init() => Promise<MethodResult<ProviderSdk>>Required

Initialize SDK provider script using config object.

login() => Promise<MethodResult<AuthData>>Required

Calls provider login.

logout() => Promise<MethodResult<null>>Required

Calls provider logout.

revoke() => Promise<MethodResult<any>>Required

De-authorizes app revoking all of the scopes the user granted.

Examples

Config

The config object gets distributed to each provider's adapter. You can modify the configuration or use the existing one. The configuration modification gets synchronized with local storage. Don't be afraid to refresh the page.

The default configuration can have some limitations or not be working for you in some cases. In this case create you own configuring apps to get clientId or appId:

{
"facebook":{
"debug":
booltrue
"appId":
string"448388196281027"
"cookie":
booltrue
"version":
string"v9.0"
"xfbml":
booltrue
}
"google":{
"clientId":
string"605972781713-7oms41umb38tt1tacas20r ..."
"scope":
string"profile email"
}
}

Core Methods

login()

 auth.facebook.login()
 auth.google.login()

getUserProfile()

 auth.facebook.getUserProfile()
 auth.google.getUserProfile()

grant()

 auth.facebook.grant(args)
"args":{
"scope":
string"email,ads_read"
}
 auth.google.grant(args)
"args":{
"scope":
string"https://www.googleapis.com/auth/user.gender.read"
}

api()

 auth.facebook.api(args)
"args":{
"method":
string"GET"
"params":{
"fields":
string"last_name"
}
"path":
string"/me"
}
 auth.google.api(args)
"args":{
"method":
string"GET"
"params":{
"personFields":
string"names"
}
"path":
string"https://people.googleapis.com/v1/people/me"
}

logout()

 auth.facebook.logout()
 auth.google.logout()

revoke()

 auth.facebook.revoke()
 auth.google.revoke()

autoLogin()

 auth.facebook.autoLogin()
 auth.google.autoLogin()

init()

The method gets called on the ImplicitAuthProvider mount phase. In most cases, you don't have to call it manually, but if you want to, use the following.
 auth.facebook.init()
 auth.google.init()

Event Methods

Beside core methods the ImplicitAuthProvider component passes event emitter methods. The emitter functionality comes from mitt - event emitter library. The API documentation you can find here.

When it can be helpful?

If you call core methods in multiple places but store data in a root component the events listening might be a good solution.

A core method call causes the event gets triggered("login", "logout", etc.). Also there a special error event which occurs when a core method call crashes.

Example
import { useImplicitAuth } from 'react-implicit-auth';

/**
 * Don't forget to put the following component as child of `ImplicitAuthProvider`.
 */
const Root = () => {
  const auth = useImplicitAuth();
  const [user, setUser] = useState(null);

  useEffect(() => {
    const handleLoginEvent = async () => {
      const user = await auth.getUserProfile();

      setUser(user.data);
    };

    const handleLogoutEvent = async () => {
      setUser(null);
    };

    /**
     * If autoLogin is failed it makes sense to redirect a user
     * to the login view.
     */
    const handleErrorEvent = ({ event }) => {
      if (event === 'autoLogin') {
        router.push('/login');
      }
    };

    authClient?.on?.('login', handleLoginEvent);
    authClient?.on?.('autoLogin', handleLoginEvent);
    authClient?.on?.('logout', handleLogoutEvent);
    authClient?.on?.('error', handleErrorEvent);

    return () => {
      authClient?.off?.('login', handleLoginEvent);
      authClient?.off?.('autoLogin', handleLoginEvent);
      authClient?.on?.('logout', handleLogoutEvent);
      authClient?.off?.('error', handleErrorEvent);
    };
  }, [authClient]);

  return <>{user && <span>Hello, {user.name}</span>}</>;
};

export default Root;

I hope you got the idea. In this example you see the global component that can react on every login/logout and keep this data in its state.

Policy

The default config which includes application ids for google and facebook has only a demonstration purpose. The reason for having it is to save developers time if they haven't their own application registered. If a developer has its applications registered the default config might be replaced.

Using the default config users can be sure that we don't collect, use, or share any user's data.

import { useImplicitAuth } from 'react-implicit-auth';

A custom React hook that returns API passed by <ImplicitAuthProvider />.

Be sure the hook gets called as a child of <ImplicitAuthProvider />.

import { useImplicitAuth, ImplicitAuthProvider } from 'react-implicit-auth';

const FacebookLoginButton = () => {
  const auth = useImplicitAuth();

  return <button onClick={() => auth.facebook.login()}>{children}</button>;
};

const MyApp = () => {
  return (
    <ImplicitAuthProvider
      config={{
        facebook: {
          debug: true,
          appId: '****************',
          cookie: true,
          version: 'v9.0',
          xfbml: false,
        },
      }}
    >
      <FacebookLoginButton />
    </ImplicitAuthProvider>
  );
};

export default MyApp;