signinwith 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/react.jsx +30 -40
- package/readme.md +10 -9
- package/styles.css +50 -51
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "signinwith",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Simple and straightforward library for sign in / sign up with thirdparty oAuth services like Google, Meta, Apple...",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"type": "module",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": "./index.js",
|
|
11
|
-
"./react": "./react.jsx"
|
|
11
|
+
"./react": "./react.jsx",
|
|
12
|
+
"./styles.css": "./styles.css"
|
|
12
13
|
},
|
|
13
14
|
"keywords": [
|
|
14
15
|
"signinwith",
|
package/react.jsx
CHANGED
|
@@ -1,34 +1,19 @@
|
|
|
1
1
|
import React, { useEffect, useRef } from 'react';
|
|
2
2
|
|
|
3
|
-
// Subcomponent: Meta (Facebook)
|
|
4
3
|
const FacebookIcon = () => (
|
|
5
|
-
<svg
|
|
6
|
-
<rect width="32" height="32" rx="16" fill="#1877F2"/>
|
|
7
|
-
<path d="M22 16.001h-3v8h-4v-8h-2v-3h2v-2c0-2.206 1.794-4 4-4h3v3h-3c-.553 0-1 .447-1 1v2h4l-1 3z" fill="#fff"/>
|
|
8
|
-
</svg>
|
|
4
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 666.667 666.667"><defs><clipPath clipPathUnits="userSpaceOnUse" id="a"><path d="M0 700h700V0H0Z"/></clipPath></defs><g clip-path="url(#a)" transform="matrix(1.33333 0 0 -1.33333 -133.333 800)"><path d="M600 350c0 138.071-111.929 250-250 250S100 488.071 100 350c0-117.245 80.715-215.622 189.606-242.638v166.242h-51.552V350h51.552v32.919c0 85.092 38.508 124.532 122.048 124.532 15.838 0 43.167-3.105 54.347-6.211v-69.254c-5.901.621-16.149.932-28.882.932-40.993 0-56.832-15.528-56.832-55.9V350h81.659l-14.028-76.396h-67.631V101.831C504.073 116.782 600 222.182 600 350" fill="#0866ff"/><path d="M447.918 273.604 461.947 350h-81.66v27.019c0 40.372 15.839 55.899 56.832 55.899 12.733 0 22.98-.31 28.882-.931v69.253c-11.18 3.106-38.51 6.212-54.347 6.212-83.54 0-122.048-39.441-122.048-124.533v-32.92h-51.552v-76.395h51.552V107.362A250.559 250.559 0 0 1 350 100c10.254 0 20.358.632 30.288 1.83v171.774Z" fill="#fff"/></g></svg>
|
|
9
5
|
);
|
|
10
6
|
|
|
11
7
|
const GoogleIcon = () => (
|
|
12
|
-
<svg
|
|
13
|
-
<g>
|
|
14
|
-
<circle cx="16" cy="16" r="16" fill="#fff"/>
|
|
15
|
-
<path d="M27 16.082c0-.638-.057-1.252-.163-1.837H16v3.478h6.18a5.29 5.29 0 0 1-2.293 3.47v2.885h3.7C25.98 22.13 27 19.345 27 16.082z" fill="#4285F4"/>
|
|
16
|
-
<path d="M16 27c2.43 0 4.47-.805 5.96-2.19l-3.7-2.885c-1.03.69-2.35 1.1-3.77 1.1-2.9 0-5.36-1.96-6.24-4.6h-3.8v2.89A10.997 10.997 0 0 0 16 27z" fill="#34A853"/>
|
|
17
|
-
<path d="M9.76 18.425A6.594 6.594 0 0 1 9.2 16c0-.84.15-1.655.41-2.425v-2.89h-3.8A10.997 10.997 0 0 0 5 16c0 1.73.41 3.37 1.17 4.825l3.59-2.4z" fill="#FBBC05"/>
|
|
18
|
-
<path d="M16 9.6c1.32 0 2.5.455 3.43 1.35l2.57-2.57C20.47 6.81 18.43 6 16 6A10.997 10.997 0 0 0 5.81 10.685l3.8 2.89C10.64 11.56 13.1 9.6 16 9.6z" fill="#EA4335"/>
|
|
19
|
-
</g>
|
|
20
|
-
</svg>
|
|
8
|
+
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/><path d="M1 1h22v22H1z" fill="none"/></svg>
|
|
21
9
|
);
|
|
22
10
|
|
|
23
11
|
const AppleIcon = () => (
|
|
24
|
-
<svg width="
|
|
25
|
-
<g>
|
|
26
|
-
<circle cx="16" cy="16" r="16" fill="#000"/>
|
|
27
|
-
<path d="M22.67 23.13c-.53 1.13-1.16 2.25-2.08 2.27-.89.02-1.18-.72-2.45-.72-1.27 0-1.6.7-2.44.74-.98.04-1.73-1.22-2.27-2.34-1.24-2.54-2.18-7.19.09-8.97.86-.67 2.09-.47 3.36-.47 1.26 0 2.46-.21 3.36.47 1.03.8 1.45 2.22 1.2 3.44-.25 1.22-1.01 1.82-1.01 1.82s1.13.18 1.99 1.13c.86.95.7 2.36.18 3.13zM18.6 8.8c.59-.7 1.01-1.68.89-2.67-.86.04-1.89.57-2.5 1.27-.55.62-1.04 1.62-.86 2.58.97.08 1.88-.49 2.47-1.18z" fill="#fff"/>
|
|
28
|
-
</g>
|
|
29
|
-
</svg>
|
|
12
|
+
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="814" height="1000"><path fill="#FFFFFF" d="M788.1 340.9c-5.8 4.5-108.2 62.2-108.2 190.5 0 148.4 130.3 200.9 134.2 202.2-.6 3.2-20.7 71.9-68.7 141.9-42.8 61.6-87.5 123.1-155.5 123.1s-85.5-39.5-164-39.5c-76.5 0-103.7 40.8-165.9 40.8s-105.6-57-155.5-127C46.7 790.7 0 663 0 541.8c0-194.4 126.4-297.5 250.8-297.5 66.1 0 121.2 43.4 162.7 43.4 39.5 0 101.1-46 176.3-46 28.5 0 130.9 2.6 198.3 99.2zm-234-181.5c31.1-36.9 53.1-88.1 53.1-139.3 0-7.1-.6-14.3-1.9-20.1-50.6 1.9-110.8 33.7-147.1 75.8-28.5 32.4-55.1 83.6-55.1 135.5 0 7.8 1.3 15.6 1.9 18.1 3.2.6 8.4 1.3 13.6 1.3 45.4 0 102.5-30.4 135.5-71.3z"/></svg>
|
|
30
13
|
);
|
|
31
|
-
|
|
14
|
+
|
|
15
|
+
// Subcomponent: Facebook (Facebook)
|
|
16
|
+
export function SignInWithFacebook({ service, onSignin, onError }) {
|
|
32
17
|
useEffect(() => {
|
|
33
18
|
if (!window.FB) {
|
|
34
19
|
window.fbAsyncInit = function () {
|
|
@@ -50,18 +35,20 @@ export function SignInWithMeta({ service, onSignin }) {
|
|
|
50
35
|
}
|
|
51
36
|
}, [service.appId]);
|
|
52
37
|
|
|
53
|
-
const handleLogin = () => {
|
|
38
|
+
const handleLogin = (e) => {
|
|
39
|
+
e.stopPropagation();
|
|
40
|
+
e.preventDefault();
|
|
54
41
|
window.FB.login(function (response) {
|
|
55
42
|
if (response.authResponse) {
|
|
56
|
-
onSignin('
|
|
43
|
+
onSignin('facebook', { accessToken: response.authResponse.accessToken });
|
|
57
44
|
}
|
|
58
45
|
}, { scope: 'email,public_profile' });
|
|
59
46
|
};
|
|
60
47
|
|
|
61
|
-
return <button className="signinwith-button signinwith-button-
|
|
48
|
+
return <button className="signinwith-button signinwith-button-facebook" onClick={handleLogin}><FacebookIcon />Continue with Facebook</button>;
|
|
62
49
|
}
|
|
63
50
|
// Subcomponent: Google
|
|
64
|
-
export function SignInWithGoogle({ service, onSignin }) {
|
|
51
|
+
export function SignInWithGoogle({ service, onSignin, onError }) {
|
|
65
52
|
useEffect(() => {
|
|
66
53
|
const script = document.createElement('script');
|
|
67
54
|
script.src = 'https://accounts.google.com/gsi/client';
|
|
@@ -70,6 +57,7 @@ export function SignInWithGoogle({ service, onSignin }) {
|
|
|
70
57
|
script.onload = () => {
|
|
71
58
|
window.google.accounts.id.initialize({
|
|
72
59
|
client_id: service.clientId,
|
|
60
|
+
use_fedcm_for_prompt: true,
|
|
73
61
|
callback: (res) => {
|
|
74
62
|
onSignin('google', { credential: res.credential });
|
|
75
63
|
}
|
|
@@ -85,13 +73,11 @@ export function SignInWithGoogle({ service, onSignin }) {
|
|
|
85
73
|
};
|
|
86
74
|
}, [service.clientId]);
|
|
87
75
|
|
|
88
|
-
const handleGoogleLogin = () => {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
},
|
|
94
|
-
scopes: ['email', 'profile']
|
|
76
|
+
const handleGoogleLogin = (e) => {
|
|
77
|
+
e.stopPropagation();
|
|
78
|
+
e.preventDefault();
|
|
79
|
+
window.google.accounts.id.prompt((notification) => {
|
|
80
|
+
onError?.(notification.getDismissedReason() || 'Sign-in with Google failed.');
|
|
95
81
|
});
|
|
96
82
|
};
|
|
97
83
|
|
|
@@ -103,7 +89,7 @@ export function SignInWithGoogle({ service, onSignin }) {
|
|
|
103
89
|
}
|
|
104
90
|
|
|
105
91
|
// Subcomponent: Apple
|
|
106
|
-
export function SignInWithApple({ service, onSignin }) {
|
|
92
|
+
export function SignInWithApple({ service, onSignin, onError }) {
|
|
107
93
|
useEffect(() => {
|
|
108
94
|
const script = document.createElement('script');
|
|
109
95
|
script.src = 'https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js';
|
|
@@ -120,18 +106,22 @@ export function SignInWithApple({ service, onSignin }) {
|
|
|
120
106
|
};
|
|
121
107
|
document.body.appendChild(script);
|
|
122
108
|
}, [service.clientId]);
|
|
123
|
-
|
|
124
|
-
|
|
109
|
+
const handleAppleLogin = (e) => {
|
|
110
|
+
e.stopPropagation();
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
window.AppleID.auth.signIn();
|
|
113
|
+
};
|
|
114
|
+
return <button className="signinwith-button signinwith-button-apple" onClick={handleAppleLogin}><AppleIcon />Continue with Apple</button>;
|
|
125
115
|
}
|
|
126
116
|
|
|
127
117
|
// Main SignInWith Component
|
|
128
|
-
export default function SignInWith({ onSignin, services, theme = 'light' }) {
|
|
118
|
+
export default function SignInWith({ onSignin, onError, services, theme = 'light' }) {
|
|
129
119
|
return (
|
|
130
|
-
<div
|
|
120
|
+
<div className={`signinwith-container signinwith-theme-${theme}`}>
|
|
131
121
|
{Object.entries(services).map(([key, config]) => {
|
|
132
|
-
if (key === 'google') return <SignInWithGoogle key={key} service={config} onSignin={onSignin} />;
|
|
133
|
-
if (key === '
|
|
134
|
-
if (key === 'apple') return <SignInWithApple key={key} service={config} onSignin={onSignin} />;
|
|
122
|
+
if (key === 'google') return <SignInWithGoogle key={key} service={config} onSignin={onSignin} onError={onError} />;
|
|
123
|
+
if (key === 'facebook') return <SignInWithFacebook key={key} service={config} onSignin={onSignin} onError={onError} />;
|
|
124
|
+
if (key === 'apple') return <SignInWithApple key={key} service={config} onSignin={onSignin} onError={onError} />;
|
|
135
125
|
return null;
|
|
136
126
|
})}
|
|
137
127
|
</div>
|
package/readme.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# Sign In With
|
|
2
2
|
|
|
3
|
-
A simple and straightforward library for adding "Sign in with..." buttons (Google, Meta
|
|
3
|
+
A simple and straightforward library for adding "Sign in with..." buttons (Google, Facebook/Meta, Apple) to your web application, handling both the frontend UI (React) and backend verification.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
* Easy integration for Google,
|
|
7
|
+
* Easy integration for Google, Facebook (Meta), and Apple sign-in.
|
|
8
8
|
* React components for the frontend buttons.
|
|
9
9
|
* Backend utility functions to verify the identity tokens/access tokens.
|
|
10
10
|
* Basic customizable styling.
|
|
@@ -65,7 +65,7 @@ function App() {
|
|
|
65
65
|
return (
|
|
66
66
|
<div className="signinwith-container">
|
|
67
67
|
<h2>Sign In</h2>
|
|
68
|
-
<SignInWith services={services} onSignin={handleSignin} />
|
|
68
|
+
<SignInWith services={services} onSignin={handleSignin} onError={error=>console.error(error)} />
|
|
69
69
|
</div>
|
|
70
70
|
);
|
|
71
71
|
}
|
|
@@ -76,7 +76,8 @@ export default App;
|
|
|
76
76
|
### Props for `SignInWith`
|
|
77
77
|
|
|
78
78
|
* `services` (Object, required): An object where keys are the service names (`google`, `meta`, `apple`) and values are their respective configuration objects.
|
|
79
|
-
* `onSignin` (Function, required): A callback function that receives `(serviceName, data)` when a sign-in attempt is successful on the client-side. `data` contains the necessary information (e.g., `credential` for Google, `accessToken` for
|
|
79
|
+
* `onSignin` (Function, required): A callback function that receives `(serviceName, data)` when a sign-in attempt is successful on the client-side. `data` contains the necessary information (e.g., `credential` for Google, `accessToken` for Facebook, `authorization` object for Apple) to be sent to your backend for verification.
|
|
80
|
+
* `onError` (Function, optional): A callback function that receives an error string if there's an issue during the sign-in process.
|
|
80
81
|
|
|
81
82
|
## Backend Verification
|
|
82
83
|
|
|
@@ -96,8 +97,8 @@ const servicesConfig = {
|
|
|
96
97
|
google: {
|
|
97
98
|
clientId: process.env.GOOGLE_CLIENT_ID,
|
|
98
99
|
},
|
|
99
|
-
|
|
100
|
-
//
|
|
100
|
+
facebook: {
|
|
101
|
+
// Facebook verification only needs the access token from the frontend
|
|
101
102
|
// No specific backend config needed here for the library function itself
|
|
102
103
|
// but you might need App ID/Secret for other Graph API calls.
|
|
103
104
|
},
|
|
@@ -145,7 +146,7 @@ The main `verifySignin` function delegates to service-specific functions:
|
|
|
145
146
|
* `verifySigninGoogle(config, verificationData)`: Verifies Google ID token.
|
|
146
147
|
* `config`: Needs `{ clientId }`.
|
|
147
148
|
* `verificationData`: Needs `{ credential }`.
|
|
148
|
-
* `
|
|
149
|
+
* `verifySigninFacebook(config, verificationData)`: Verifies Facebook access token by fetching user email.
|
|
149
150
|
* `config`: Not directly used by the function, but you need your App ID configured on the frontend.
|
|
150
151
|
* `verificationData`: Needs `{ accessToken }`.
|
|
151
152
|
* `verifySigninApple(config, verificationData)`: Verifies Apple ID token.
|
|
@@ -171,8 +172,8 @@ You can override these styles in your own CSS. The container in the example uses
|
|
|
171
172
|
* Add your domain(s) to "Authorized JavaScript origins".
|
|
172
173
|
* Add your backend callback URL (if applicable) to "Authorized redirect URIs".
|
|
173
174
|
* Get your **Client ID**.
|
|
174
|
-
* **
|
|
175
|
-
* Create an App at [
|
|
175
|
+
* **Facebook (Meta):**
|
|
176
|
+
* Create an App at [Facebook for Developers](https://developers.facebook.com/).
|
|
176
177
|
* Set up "Facebook Login for Business".
|
|
177
178
|
* Add your domain(s) to the App Domains and Site URL in the app settings.
|
|
178
179
|
* Get your **App ID**.
|
package/styles.css
CHANGED
|
@@ -1,56 +1,55 @@
|
|
|
1
|
-
.signinwith-
|
|
2
|
-
display:
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
&:hover {
|
|
31
|
-
background-color: #166FE5;
|
|
1
|
+
.signinwith-container {
|
|
2
|
+
display: flex;
|
|
3
|
+
gap: 10px;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
align-items: stretch;
|
|
6
|
+
padding:10px 0px;
|
|
7
|
+
.signinwith-button {
|
|
8
|
+
display: inline-flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
justify-content: center;
|
|
11
|
+
padding: 10px 24px;
|
|
12
|
+
border: 1px solid #dadce0;
|
|
13
|
+
border-radius: 4px;
|
|
14
|
+
font-size: 14px;
|
|
15
|
+
font-weight: 500;
|
|
16
|
+
cursor: pointer;
|
|
17
|
+
text-align: center;
|
|
18
|
+
text-decoration: none;
|
|
19
|
+
align-self: stretch;
|
|
20
|
+
box-sizing: border-box;
|
|
21
|
+
transition: background-color 0.3s ease, border-color 0.3s ease;
|
|
22
|
+
color: #3c4043;
|
|
23
|
+
background-color: #ffffff;
|
|
24
|
+
|
|
25
|
+
& svg {
|
|
26
|
+
width:auto;
|
|
27
|
+
height:20px;
|
|
28
|
+
margin-right: 4px;
|
|
32
29
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
&-apple {
|
|
36
|
-
background-color: #000000;
|
|
37
|
-
color: white;
|
|
38
|
-
border-color: #000000;
|
|
39
|
-
|
|
30
|
+
|
|
40
31
|
&:hover {
|
|
41
|
-
background-color: #
|
|
32
|
+
background-color: #f8f9fa;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
&.signinwith-button-facebook {
|
|
36
|
+
background-color: #1877F2;
|
|
37
|
+
color: white;
|
|
38
|
+
border-color: #0866ff;
|
|
39
|
+
|
|
40
|
+
&:hover {
|
|
41
|
+
background-color: #0866ff;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&.signinwith-button-apple {
|
|
46
|
+
background-color: #000000;
|
|
47
|
+
color: white;
|
|
48
|
+
border-color: #000000;
|
|
49
|
+
|
|
50
|
+
&:hover {
|
|
51
|
+
background-color: #333333;
|
|
52
|
+
}
|
|
42
53
|
}
|
|
43
54
|
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
#google-signin-btn > div {
|
|
48
|
-
margin: 0 !important;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.signinwith-container {
|
|
52
|
-
display: flex;
|
|
53
|
-
gap: 1rem;
|
|
54
|
-
flex-direction: column;
|
|
55
|
-
align-items: center;
|
|
56
55
|
}
|