diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bd2a177 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,120 @@ +# Contributing to @react-oauth + +Thank you for your interest in contributing to @react-oauth! This document provides guidelines and instructions for contributing. + +## Getting Started + +1. Fork the repository +2. Clone your fork: `git clone https://github.com/yourusername/react-oauth.git` +3. Install dependencies: `yarn install` +4. Create a branch: `git checkout -b feature/your-feature-name` + +## Development Workflow + +### Building + +```bash +# Build all packages +yarn build + +# Start development mode for all packages +yarn dev + +# Start development mode for Google package only +yarn dev:google +``` + +### Linting & Formatting + +We use Prettier for code formatting. Code is automatically formatted on commit via lint-staged. + +```bash +# Check code formatting +yarn prettier:check + +# Auto-fix formatting issues +yarn prettier:fix +``` + +### Committing Changes + +We use [Commitizen](https://github.com/commitizen/cz-cli) for creating properly formatted commit messages following [Conventional Commits](https://www.conventionalcommits.org/): + +```bash +yarn commit +``` + +This will guide you through creating a commit message interactively. + +## Code Style + +- We use TypeScript with strict mode enabled +- We use Prettier for code formatting (runs automatically on commit) +- Follow the existing code style in the repository +- Write meaningful commit messages using Conventional Commits +- Run `yarn prettier:fix` before committing to ensure formatting + +## Adding a New OAuth Provider + +1. Create a new package directory under `packages/@react-oauth/` +2. Follow the structure of `packages/@react-oauth/github/` +3. Implement the OAuth flow for your provider +4. Update the root README.md +5. Create a changeset: `yarn changeset` + +## Pull Request Process + +1. Run `yarn build` to ensure everything builds successfully +2. Run `yarn prettier:check` to ensure formatting is correct +3. Update documentation if needed +4. Create a changeset if this is a user-facing change: `yarn changeset` +5. Submit your pull request with a clear description + +## Commit Messages + +We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. Use `yarn commit` for interactive commit creation. + +**Format:** + +``` +(): +``` + +**Types:** + +- `feat:` A new feature +- `fix:` A bug fix +- `docs:` Documentation only changes +- `style:` Code style changes (formatting, etc.) +- `refactor:` Code refactoring +- `test:` Adding or updating tests +- `chore:` Maintenance tasks + +**Scopes:** + +- `google` - `@react-oauth/google` package +- `github` - `@react-oauth/github` package +- `playground` - Playground app +- `repo` - Repository config/tooling + +**Examples:** + +``` +feat(google): add custom button themes +fix(github): handle popup blocked error +docs(repo): update contributing guide +``` + +## Versioning + +This project uses [Changesets](https://github.com/changesets/changesets) for version management. If your PR includes user-facing changes: + +1. Create a changeset: `yarn changeset` +2. Select the affected packages +3. Choose the type of change (major, minor, patch) +4. Write a summary of the changes +5. Commit the changeset file with your changes + +## Questions? + +Feel free to open an issue for any questions or concerns. diff --git a/README.md b/README.md index 3c2db68..9ddd23d 100644 --- a/README.md +++ b/README.md @@ -1,273 +1,162 @@ -# React OAuth2 | Google +
-Google OAuth2 using the new [**Google Identity Services SDK**](https://developers.google.com/identity/gsi/web) for React [@react-oauth/google](https://www.npmjs.com/package/@react-oauth/google)🚀 +# React OAuth -## Install +**Modern OAuth2 authentication libraries for React** 🚀 -```sh -$ npm install @react-oauth/google@latest +[![npm version](https://img.shields.io/npm/v/@react-oauth/google.svg)](https://www.npmjs.com/package/@react-oauth/google) +[![npm version](https://img.shields.io/npm/v/@react-oauth/github.svg)](https://www.npmjs.com/package/@react-oauth/github) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -# or - -$ yarn add @react-oauth/google@latest -``` - -## Demo & How to use to fetch user details - -https://react-oauth.vercel.app/ - -## Seamless sign-in and sign-up flows - -### Sign In With Google - -Add a personalized and customizable sign-up or sign-in button to your website. - -![personalized button](https://developers.google.com/identity/gsi/web/images/personalized-button-single_480.png) +[Demo](https://react-oauth.vercel.app/) • [Documentation](#documentation) • [GitHub](https://github.com/MomenSherif/react-oauth) -### One-tap sign-up +
-Sign up new users with just one tap, without interrupting them with a sign-up screen. Users get a secure, token-based, passwordless account on your site, protected by their Google Account. +--- -![One-tap sign-up](https://developers.google.com/identity/gsi/web/images/one-tap-sign-in_480.png) +## Overview -### Automatic sign-in +**React OAuth** is a collection of production-ready OAuth2 libraries for React applications. Each package is designed to be simple, type-safe, and easy to integrate into your projects. -Sign users in automatically when they return to your site on any device or browser, even after their session expires. +### Packages -![Automatic sign-in](https://developers.google.com/identity/gsi/web/images/auto-sign-in_480.png) +| Package | Description | NPM | +| ------------------------------------------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| **[@react-oauth/google](./packages/@react-oauth/google/README.md)** | Google OAuth2 using the new Google Identity Services SDK | [![npm](https://img.shields.io/npm/v/@react-oauth/google.svg)](https://www.npmjs.com/package/@react-oauth/google) | +| **[@react-oauth/github](./packages/@react-oauth/github/README.md)** | Modern React hook for GitHub OAuth authentication | [![npm](https://img.shields.io/npm/v/@react-oauth/github.svg)](https://www.npmjs.com/package/@react-oauth/github) | -## User authorization for Google APIs (with custom button) +--- -OAuth 2.0 implicit and authorization code flows for web apps +## Quick Start -> The Google Identity Services JavaScript library helps you to quickly and safely obtain access tokens necessary to call Google APIs. Your web application, complete either the OAuth 2.0 implicit flow, or to initiate the authorization code flow which then finishes on your backend platform. +### Google OAuth -## How to use - -1. Get your [**Google API client ID**](https://console.cloud.google.com/apis/dashboard) - -> Key Point: Add both `http://localhost` and `http://localhost:` to the Authorized JavaScript origins box for local tests or development. - -2. Configure your OAuth [**Consent Screen**](https://console.cloud.google.com/apis/credentials/consent) +```bash +npm install @react-oauth/google +# or +yarn add @react-oauth/google +``` -3. Wrap your application with `GoogleOAuthProvider` +**Basic Usage:** ```jsx -import { GoogleOAuthProvider } from '@react-oauth/google'; - -...; +import { GoogleOAuthProvider, GoogleLogin } from '@react-oauth/google'; + +function App() { + return ( + + { + console.log(credentialResponse); + }} + onError={() => { + console.log('Login Failed'); + }} + /> + + ); +} ``` -### Sign In With Google +**Features:** -```jsx -import { GoogleLogin } from '@react-oauth/google'; - - { - console.log(credentialResponse); - }} - onError={() => { - console.log('Login Failed'); - }} -/>; -``` +- ✅ Sign In With Google button +- ✅ One-tap sign-up +- ✅ Automatic sign-in +- ✅ Custom login buttons +- ✅ Implicit & Authorization Code flows +- ✅ Full TypeScript support -> If you are using popup mode (default), set the proper [Cross Origin Opener Policy](https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid#cross_origin_opener_policy) to avoid the [blank window issue](https://github.com/google/google-api-javascript-client/issues/796): `cross-origin-opener-policy: same-origin-allow-popups`. +### 📖 [View Full Google Documentation →](./packages/@react-oauth/google/README.md) -### One-tap +--- -```jsx -import { useGoogleOneTapLogin } from '@react-oauth/google'; - -useGoogleOneTapLogin({ - onSuccess: credentialResponse => { - console.log(credentialResponse); - }, - onError: () => { - console.log('Login Failed'); - }, -}); +### GitHub OAuth + +```bash +npm install @react-oauth/github +# or +yarn add @react-oauth/github ``` -or +**Basic Usage:** ```jsx -import { GoogleLogin } from '@react-oauth/google'; - - { - console.log(credentialResponse); - }} - onError={() => { - console.log('Login Failed'); - }} - useOneTap -/>; +import { useGitHubLogin } from '@react-oauth/github'; + +function LoginButton() { + const { initiateGitHubLogin, isLoading } = useGitHubLogin({ + clientId: 'your-github-client-id', + redirectUri: 'http://localhost:3000/callback', + onSuccess: response => { + console.log('Authorization code:', response.code); + // Exchange code for access token on your backend + }, + onError: error => { + console.error('Authentication failed:', error); + }, + }); + + return ( + + ); +} ``` -> If you are using one tap login, when logging user out consider [this issue](https://developers.google.com/identity/gsi/web/guides/automatic-sign-in-sign-out#sign-out) may happen, to prevent it call `googleLogout` when logging user out from your application. - -```jsx -import { googleLogout } from '@react-oauth/google'; +**Features:** -googleLogout(); -``` +- ✅ Production-ready React hook +- ✅ Fully typed with TypeScript +- ✅ Zero runtime dependencies +- ✅ Flexible API with complete UI control +- ✅ Comprehensive error handling +- ✅ Built-in CSRF protection -### Automatic sign-in +### 📖 [View Full GitHub Documentation →](./packages/@react-oauth/github/README.md) -> `auto_select` prop `true` +--- -```jsx +## Documentation - +### Google OAuth -useGoogleOneTapLogin({ - ... - auto_select -}); -``` +- **[Complete API Reference 🚀](./packages/@react-oauth/google/README.md)** - Full documentation with all props, hooks, and examples +- **[Google Identity Services Docs](https://developers.google.com/identity/gsi/web)** - Official Google documentation +- **[Live Demo](https://react-oauth.vercel.app/)** - Interactive playground for Google OAuth -### Custom login button (implicit & authorization code flow) +### GitHub OAuth -#### Implicit flow +- **[Complete API Reference 🚀](./packages/@react-oauth/github/README.md)** - Full documentation with examples and error handling +- **[GitHub OAuth Docs](https://docs.github.com/en/developers/apps/building-oauth-apps)** - Official GitHub OAuth documentation -```jsx -import { useGoogleLogin } from '@react-oauth/google'; +--- -const login = useGoogleLogin({ - onSuccess: tokenResponse => console.log(tokenResponse), -}); +## Demo - login()}>Sign in with Google 🚀; -``` +Check out the live demo to see the Google OAuth package in action: -#### Authorization code flow +🔗 **[https://react-oauth.vercel.app/](https://react-oauth.vercel.app/)** _(Google OAuth only)_ -> Requires backend to exchange code with access and refresh token. +--- -```jsx -import { useGoogleLogin } from '@react-oauth/google'; +## Contributing -const login = useGoogleLogin({ - onSuccess: codeResponse => console.log(codeResponse), - flow: 'auth-code', -}); +Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests. - login()}>Sign in with Google 🚀; -``` +--- -#### Checks if the user granted all the specified scope or scopes +## License -```jsx -import { hasGrantedAllScopesGoogle } from '@react-oauth/google'; +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. -const hasAccess = hasGrantedAllScopesGoogle( - tokenResponse, - 'google-scope-1', - 'google-scope-2', -); -``` +--- -#### Checks if the user granted any of the specified scope or scopes +
-```jsx -import { hasGrantedAnyScopeGoogle } from '@react-oauth/google'; +Made with ❤️ for the React community -const hasAccess = hasGrantedAnyScopeGoogle( - tokenResponse, - 'google-scope-1', - 'google-scope-2', -); -``` +**[GitHub](https://github.com/MomenSherif/react-oauth)** • **[Issues](https://github.com/MomenSherif/react-oauth/issues)** • [@react-oauth/google](https://www.npmjs.com/package/@react-oauth/google) • [@react-oauth/github](https://www.npmjs.com/package/@react-oauth/github) -#### [Content Security Policy (if needed)](https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid#content_security_policy) - -## API - -### GoogleOAuthProvider - -| Required | Prop | Type | Description | -| :------: | ------------------- | ---------- | --------------------------------------------------------------------------- | -| ✓ | clientId | `string` | [**Google API client ID**](https://console.cloud.google.com/apis/dashboard) | -| | nonce | `string` | Nonce applied to GSI script tag. Propagates to GSI's inline style tag | -| | onScriptLoadSuccess | `function` | Callback fires on load gsi script success | -| | onScriptLoadError | `function` | Callback fires on load gsi script failure | - -### GoogleLogin - -| Required | Prop | Type | Description | -| :------: | ---------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ✓ | onSuccess | `(response: CredentialResponse) => void` | Callback fires with credential response after successfully login | -| | onError | `function` | Callback fires after login failure | -| | type | `standard` \| `icon` | Button type [type](https://developers.google.com/identity/gsi/web/reference/js-reference#type) | -| | theme | `outline` \| `filled_blue` \| `filled_black` | Button [theme](https://developers.google.com/identity/gsi/web/reference/js-reference#theme) | -| | size | `large` \| `medium` \| `small` | Button [size](https://developers.google.com/identity/gsi/web/reference/js-reference#size) | -| | text | `signin_with` \| `signup_with` \| `continue_with` \| `signin` | Button [text](https://developers.google.com/identity/gsi/web/reference/js-reference#text). For example, "Sign in with Google", "Sign up with Google" or "Sign in" | -| | shape | `rectangular` \| `pill` \| `circle` \| `square` | Button [shape](https://developers.google.com/identity/gsi/web/reference/js-reference#shape) | -| | logo_alignment | `left` \| `center` | Google [logo alignment](https://developers.google.com/identity/gsi/web/reference/js-reference#logo_alignment) | -| | width | `string` | button [width](https://developers.google.com/identity/gsi/web/reference/js-reference#width), in pixels | -| | locale | `string` | If set, then the button [language](https://developers.google.com/identity/gsi/web/reference/js-reference#locale) is rendered | -| | useOneTap | `boolean` | Activate One-tap sign-up or not | -| | promptMomentNotification | `(notification: PromptMomentNotification) => void` | [PromptMomentNotification](https://developers.google.com/identity/gsi/web/reference/js-reference) methods and description | -| | cancel_on_tap_outside | `boolean` | Controls whether to cancel the prompt if the user clicks outside of the prompt | -| | auto_select | `boolean` | Enables automatic selection on Google One Tap | -| | ux_mode | `popup` \| `redirect` | The Sign In With Google button UX flow | -| | login_uri | `string` | The URL of your login endpoint | -| | native_login_uri | `string` | The URL of your password credential handler endpoint | -| | native_callback | `(response: { id: string; password: string }) => void` | The JavaScript password credential handler function name | -| | prompt_parent_id | `string` | The DOM ID of the One Tap prompt container element | -| | nonce | `string` | A random string for ID tokens | -| | context | `signin` \| `signup` \| `use` | The title and words in the One Tap prompt | -| | state_cookie_domain | `string` | If you need to call One Tap in the parent domain and its subdomains, pass the parent domain to this attribute so that a single shared cookie is used | -| | allowed_parent_origin | `string` \| `string[]` | The origins that are allowed to embed the intermediate iframe. One Tap will run in the intermediate iframe mode if this attribute presents | -| | intermediate_iframe_close_callback | `function` | Overrides the default intermediate iframe behavior when users manually close One Tap | -| | itp_support | `boolean` | Enables upgraded One Tap UX on ITP browsers | -| | hosted_domain | `string` | If your application knows the Workspace domain the user belongs to, use this to provide a hint to Google. For more information, see the [hd](https://developers.google.com/identity/protocols/oauth2/openid-connect#authenticationuriparameters) field in the OpenID Connect docs | -| | use_fedcm_for_prompt | `boolean` | Allow the browser to control user sign-in prompts and mediate the sign-in flow between your website and Google. | -| | use_fedcm_for_button | `boolean` | Enable FedCM Button flow. | - -### useGoogleLogin (Both implicit & authorization code flow) - -| Required | Prop | Type | Description | -| :------: | --------------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| | flow | `implicit` \| `auth-code` | [Two flows](https://developers.google.com/identity/oauth2/web/guides/how-user-authz-works), implicit and authorization code are discussed. Both return an access token suitable for use with Google APIs | -| | onSuccess | `(response: TokenResponse\|CodeResponse) => void` | Callback fires with response ([token](https://developers.google.com/identity/oauth2/web/reference/js-reference#TokenResponse) \| [code](https://developers.google.com/identity/oauth2/web/reference/js-reference#CodeResponse)) based on flow selected after successfully login | -| | onError | `(errorResponse: {error: string; error_description?: string,error_uri?: string}) => void` | Callback fires after login failure | -| | onNonOAuthError | `(nonOAuthError: NonOAuthError) => void` | Some non-OAuth errors, such as the popup window is failed to open or closed before an OAuth response is returned. `popup_failed_to_open` \| `popup_closed` \| `unknown` | -| | scope | `string` | A space-delimited list of scopes that are approved by the user | -| | enable_serial_consent | `boolean` | defaults to true. If set to false, [more granular Google Account permissions](https://developers.googleblog.com/2018/10/more-granular-google-account.html) will be disabled for clients created before 2019. No effect for newer clients, since more granular permissions is always enabled for them. | -| | hint | `string` | If your application knows which user should authorize the request, it can use this property to provide a hint to Google. The email address for the target user. For more information, see the [login_hint](https://developers.google.com/identity/protocols/oauth2/openid-connect#authenticationuriparameters) field in the OpenID Connect docs | -| | hosted_domain | `string` | If your application knows the Workspace domain the user belongs to, use this to provide a hint to Google. For more information, see the [hd](https://developers.google.com/identity/protocols/oauth2/openid-connect#authenticationuriparameters) field in the OpenID Connect docs | - -### useGoogleLogin (Extra implicit flow props) - -| Required | Prop | Type | Description | -| :------: | ------ | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| | prompt | `''` \| `none` \| `consent` \| `select_account` | defaults to 'select_account'. A space-delimited, case-sensitive list of prompts to present the user | -| | state | `string` | Not recommended. Specifies any string value that your application uses to maintain state between your authorization request and the authorization server's response | - -### useGoogleLogin (Extra authorization code flow props) - -| Required | Prop | Type | Description | -| :------: | -------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| | ux_mode | `popup` \| `redirect` | The UX mode to use for the authorization flow. By default, it will open the consent flow in a popup. Valid values are popup and redirect | -| | redirect_uri | `string` | Required for redirect UX. Determines where the API server redirects the user after the user completes the authorization flow The value must exactly match one of the authorized redirect URIs for the OAuth 2.0 client which you configured in the API Console and must conform to our [Redirect URI validation](https://developers.google.com/identity/protocols/oauth2/web-server#uri-validation) rules. The property will be ignored by the popup UX | -| | state | `string` | Recommended for redirect UX. Specifies any string value that your application uses to maintain state between your authorization request and the authorization server's response | -| | select_account | `boolean` | defaults to 'false'. Boolean value to prompt the user to select an account | - -### useGoogleOneTapLogin - -| Required | Prop | Type | Description | -| :------: | ------------------------ | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ✓ | onSuccess | `(response: CredentialResponse) => void` | Callback fires with credential response after successfully login | -| | onError | `function` | Callback fires after login failure | -| | promptMomentNotification | `(notification: PromptMomentNotification) => void` | [PromptMomentNotification](https://developers.google.com/identity/gsi/web/reference/js-reference) methods and description | -| | cancel_on_tap_outside | `boolean` | Controls whether to cancel the prompt if the user clicks outside of the prompt | -| | hosted_domain | `string` | If your application knows the Workspace domain the user belongs to, use this to provide a hint to Google. For more information, see the [hd](https://developers.google.com/identity/protocols/oauth2/openid-connect#authenticationuriparameters) field in the OpenID Connect docs | -| | disabled | `boolean` | Controls whether to cancel the popup in cases such as when the user is already logged in | -| | use_fedcm_for_prompt | `boolean` | Allow the browser to control user sign-in prompts and mediate the sign-in flow between your website and Google. | -| | use_fedcm_for_button | `boolean` | Enable FedCM Button flow. | +
diff --git a/apps/playground/public/index.html b/apps/playground/public/index.html index 473b58a..c0aab2d 100644 --- a/apps/playground/public/index.html +++ b/apps/playground/public/index.html @@ -46,7 +46,7 @@