ra-auth-google
TypeScript icon, indicating that this package has built-in type declarations

2.0.0 • Public • Published

ra-auth-google

An auth provider for react-admin that handles authentication using the Google Identity Services (GIS).

It allows to easily enable users to sign to your app in using their Google account, either personal, or professional via Google Workspaces.

ra-auth-google

This package provides:

  • An authProvider to use with your react-admin app
  • A <LoginButton> component to render the Sign in with Google button
  • A <OneTapButton> component to enable the One Tap feature on your website
  • An httpClient to make authenticated requests to your API
  • A helper hook called useGoogleAuthProvider, allowing to configure all of the above from a single configuration object
  • A helper component called <GoogleAuthContextProvider>, allowing to expose the GSI params to the children components like <LoginButton> and <OneTapButton>

Supported Features

The following features are not (yet) included in this demo, but should also be supported:

Limitations

Since they would require a back-end, the following features are not supported by this package:

It's up to you to implement these features in your back-end if you need them.

Installation

yarn add ra-auth-google
# or
npm install --save ra-auth-google

Basic Usage

The following example implements Sign in with Google button in popup mode, using the client id configured in the .env file.

# in .env
VITE_GOOGLE_CLIENT_ID="my-application-client-id.apps.googleusercontent.com"
<!-- in index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Add the following line to load the Google Identity Services library -->
    <script async defer src="https://accounts.google.com/gsi/client"></script>
  </head>
  <body>
    <!-- ... -->
  </body>
</html>
// in src/App.tsx
import React from "react";
import { Admin, Resource, Login } from "react-admin";
import {
    useGoogleAuthProvider,
    GoogleAuthContextProvider,
    LoginButton,
} from 'ra-auth-google';
import dataProvider from "./dataProvider";
import posts from "./posts";

const App = () => {
  const { authProvider, gsiParams } = useGoogleAuthProvider();

  const LoginPage = () => (
    <Login>
      <LoginButton theme="filled_black" />
    </Login>
  );

  return (
    // Wrap your Admin with GoogleAuthContextProvider to expose the gsiParams to the children components
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
      </Admin>
    </GoogleAuthContextProvider>
  );
};
export default App;

Tip: This example uses the <Login> component provided by react-admin to create the login page. You can also include the <LoginButton> component in your own login page if you prefer.

Tip: Remember to wrap your <Admin> with <GoogleAuthContextProvider> to expose the gsiParams to the children components, like the <LoginButton>.

LoginPage

Providing Client ID Via Props

You can also provide the client id via a prop instead of using the .env file.

// in src/App.tsx
import React from 'react';
import { Admin, Resource, Login } from 'react-admin';
import {
    useGoogleAuthProvider,
    GoogleAuthContextProvider,
    LoginButton,
} from 'ra-auth-google';
import dataProvider from './dataProvider';
import posts from './posts';

const App = () => {
  const { authProvider, gsiParams } = useGoogleAuthProvider({
    client_id: "my-application-client-id.apps.googleusercontent.com",
  });

  const LoginPage = () => (
    <Login>
      <LoginButton />
    </Login>
  );

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
      </Admin>
    </GoogleAuthContextProvider>
   );
};
export default App;

One Tap Button

The <OneTapButton> component can be used to enable the One Tap button on one or more pages.

OneTapButton

It can be used as a standalone component, or to wrap a page.

import { OneTapButton } from "ra-auth-google";

const Standalone = () => {
  return (
    <div>
      <OneTapButton />
      <h1>My Page</h1>
    </div>
  )
};

const Wrapper = () => {
  return (
    <OneTapButton>
      <div>
        <h1>My Page</h1>
      </div>
    </OneTapButton>
  )
};

Tip: Remember to wrap your <Admin> with <GoogleAuthContextProvider> to expose the gsiParams to the children components that need it, like the <OneTapButton>.

Here is a full example enabling the One Tap button on a custom route:

// in src/App.tsx
import React from "react";
import { Admin, Resource, Login, CustomRoutes } from "react-admin";
import { Route } from "react-router-dom";
import { useGoogleAuthProvider, LoginButton, OneTapButton, GoogleAuthContextProvider } from "ra-auth-google";
import dataProvider from "./dataProvider";
import posts from "./posts";

const App = () => {
  const { authProvider, gsiParams } = useGoogleAuthProvider();

  const LoginPage = () => (
    <Login>
      <LoginButton />
    </Login>
  );

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
        <CustomRoutes>
          <Route
            path="/custom"
            element={
              <div>
                <OneTapButton />
                <h1>My Page</h1>
              </div>
            }
          />
        </CustomRoutes>
      </Admin>
    </GoogleAuthContextProvider>
  );
};
export default App;

Customizing The Sign In With Google Button

Google does not support using your own button to sign in. However, you can customize the button, using the provided props, to better integrate it with your app.

LoginButton

You can also use the code generator to try out the different options.

For instance, here is how to use a black-filled button theme instead of the default one:

// in src/App.tsx
import React from 'react';
import { Admin, Resource, Login } from 'react-admin';
import { useGoogleAuthProvider, LoginButton, GoogleAuthContextProvider } from "ra-auth-google";
import dataProvider from './dataProvider';
import posts from './posts';

const App = () => {
  const {
    authProvider,
    gsiParams,
  } = useGoogleAuthProvider();

  const LoginPage = () => (
    <Login>
      <LoginButton theme="filled_black" />
    </Login>
  );

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
      </Admin>
    </GoogleAuthContextProvider>
   );
};
export default App;

Automatic Sign-In

You can enable Automatic sign-in by setting the auto_select param to true:

// in src/App.tsx
import React from "react";
import { Admin, Resource, Login, CustomRoutes } from "react-admin";
import { Route } from "react-router-dom";
import { useGoogleAuthProvider, LoginButton, OneTapButton, GoogleAuthContextProvider } from "ra-auth-google";
import dataProvider from "./dataProvider";
import posts from "./posts";

const App = () => {
  const { authProvider, gsiParams } = useGoogleAuthProvider({
    auto_select: true,
  });

  const LoginPage = () => (
    <Login>
      <LoginButton />
    </Login>
  );

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
        <CustomRoutes>
          <Route
            path="/custom"
            element={
              <div>
                <OneTapButton />
                <h1>My Page</h1>
              </div>
            }
          />
        </CustomRoutes>
      </Admin>
    </GoogleAuthContextProvider>
  );
};
export default App;

Configuring The Google Identity Services Library

useGoogleAuthProvider accepts all the parameters supported by the GIS library.

For example, to change the text of the title and messages in the One Tap prompt, use the context parameter:

// in src/App.tsx
import React from "react";
import { Admin, Resource, Login, CustomRoutes } from "react-admin";
import { Route } from "react-router-dom";
import { useGoogleAuthProvider, LoginButton, OneTapButton, GoogleAuthContextProvider } from "ra-auth-google";
import dataProvider from "./dataProvider";
import posts from "./posts";

const App = () => {
  const { authProvider, gsiParams } = useGoogleAuthProvider({
    context: "use",
  });

  const LoginPage = () => (
    <Login>
      <LoginButton />
    </Login>
  );

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
        <CustomRoutes>
          <Route
            path="/custom"
            element={
              <div>
                <OneTapButton />
                <h1>My Page</h1>
              </div>
            }
          />
        </CustomRoutes>
      </Admin>
    </GoogleAuthContextProvider>
  );
};
export default App;

Making Authenticated Requests To The API

ra-auth-google includes an httpClient that can be used to make authenticated requests to your API. This helper automatically adds the credentials token to the request headers.

Here is an example with ra-data-json-server:

// in src/App.tsx
import { useGoogleAuthProvider, LoginButton, GoogleAuthContextProvider } from "ra-auth-google";
import jsonServerProvider from "ra-data-json-server";
import React from "react";
import { Admin, Login, Resource } from "react-admin";
import posts from "./posts";

const App = () => {
  const { authProvider, httpClient, gsiParams } = useGoogleAuthProvider();

  const dataProvider = jsonServerProvider(
    "https://jsonplaceholder.typicode.com",
    httpClient
  );

  const LoginPage = () => (
    <Login>
      <LoginButton />
    </Login>
  );

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
      </Admin>
    </GoogleAuthContextProvider>
  );
};
export default App;

Choosing The Token Storage Strategy

By default, ra-auth-google will store the received token in localStorage, under the "token" key.

If you want to store it somewhere else, or need to use a different key, you can provide your own tokenStore:

// in src/myTokenStore.tsx
import { TokenStore } from "ra-auth-google";

export const myTokenStore: TokenStore = {
  getToken: () => localStorage.getItem("my_token"),
  setToken: (token) => localStorage.setItem("my_token", token),
  removeToken: () => localStorage.removeItem("my_token"),
};
// in src/App.tsx
import { useGoogleAuthProvider, LoginButton, GoogleAuthContextProvider } from "ra-auth-google";
import jsonServerProvider from "ra-data-json-server";
import React from "react";
import { Admin, Login, Resource } from "react-admin";
import posts from "./posts";
import { myTokenStore } from "./myTokenStore";

const App = () => {
  const { authProvider, gsiParams, httpClient } = useGoogleAuthProvider({
    tokenStore: myTokenStore,
  });

  const dataProvider = jsonServerProvider(
    "https://jsonplaceholder.typicode.com",
    httpClient
  );

  const LoginPage = () => (
    <Login>
      <LoginButton />
    </Login>
  );

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
        title="Example Admin"
        loginPage={LoginPage}
      >
        <Resource name="posts" {...posts} />
      </Admin>
    </GoogleAuthContextProvider>
  );
};
export default App;

API

useGoogleAuthProvider

Use useGoogleAuthProvider to create an authProvider, an httpClient, and obtain a gsiParams object from a single configuration object.

The gsiParams can then be exposed to the children components using the <GoogleAuthContextProvider> wrapper.

const { authProvider, httpClient, gsiParams } = useGoogleAuthProvider();

It accepts the following parameters:

  • client_id: Optional - The Google API client ID of your application. Tries to use the GOOGLE_CLIENT_ID environment variable if not provided.
  • tokenStore: Optional - The token store to use to store the token. Defaults to localStorageTokenStore.
  • Other parameters: Optional - All the other parameters are passed to the Google Identity Services library. See the documentation for the full list of supported parameters.
const { authProvider, httpClient, gsiParams } = useGoogleAuthProvider({
  client_id: "my-application-client-id.apps.googleusercontent.com",
  context: "use",
  tokenStore: myTokenStore,
});

googleAuthProvider

Returns an authProvider that can be used with react-admin.

It accepts the following parameters:

  • gsiParams: Required - Parameters for the Google Identity Services library. See the documentation for the full list of supported parameters.
  • tokenStore: Optional - The token store to use to store the token. Defaults to localStorageTokenStore.
const authProvider = googleAuthProvider({
  gsiParams: { 
    client_id: "my-application-client-id.apps.googleusercontent.com",
    ux_mode: "popup", 
  },
  tokenStore: myTokenStore,
});

<LoginButton>

Returns a component that can be used to render the Sign in with Google button.

It requires to be used inside a <GoogleAuthContextProvider>.

It accepts the following props:

  • sx: Optional - Allows to customize the MUI <Box> inside which the button is rendered. See MUI sx prop for more information.
  • Other parameters: Optional - All the other parameters are passed to the Sign in with Google button, and allow for customization. See the documentation for the full list of supported parameters.
const MyLoginButton = () => (
  <LoginButton
    theme="filled_black"
  />
);

<OneTapButton>

The <OneTapButton> can be used either as a standalone component, or as a wrapper.

It requires to be used inside a <GoogleAuthContextProvider>.

The component itself doesn't render anything, but it triggers the Google API to display the One Tap prompt if the user is not yet signed in.

Use it in the pages that you want to enable the One Tap feature on.

const Standalone = () => (
  <div>
    <OneTapButton />
    <h1>My Page</h1>
  </div>
);

const Wrapper = () => (
  <OneTapButton>
    <div>
      <h1>My Page</h1>
    </div>
  </OneTapButton>
);

googleHttpClient

Returns an httpClient that can be used to make authenticated requests to your API.

It accepts the following parameters:

  • tokenStore: Optional - The token store to use to store the token. Defaults to localStorageTokenStore.
const httpClient = googleHttpClient({ tokenStore: myTokenStore });

<GoogleAuthContextProvider>

A helper component that allows to expose the gsiParams to the children components like <LoginButton> and <OneTapButton>.

Use it to wrap your <Admin> component with the gsiParams obtained from useGoogleAuthProvider.

// in src/App.tsx
import React from "react";
import { Admin, Resource } from "react-admin";
import {
    useGoogleAuthProvider,
    GoogleAuthContextProvider,
} from 'ra-auth-google';
import dataProvider from "./dataProvider";
import posts from "./posts";

const App = () => {
  const { authProvider, gsiParams } = useGoogleAuthProvider();

  return (
    <GoogleAuthContextProvider value={gsiParams}>
      <Admin
        authProvider={authProvider}
        dataProvider={dataProvider}
      >
        <Resource name="posts" {...posts} />
      </Admin>
    </GoogleAuthContextProvider>
  );
};

Demo

You can find a working demo, along with the source code, in this project's repository: https://github.com/marmelab/ra-auth-google

License

This auth provider is licensed under the MIT License and sponsored by marmelab.

Readme

Keywords

none

Package Sidebar

Install

npm i ra-auth-google

Weekly Downloads

218

Version

2.0.0

License

MIT

Unpacked Size

118 kB

Total Files

65

Last publish

Collaborators

  • fzaninotto
  • djhi