Skip to content

Commit

Permalink
Merge pull request anthonyjgrove#110 from anthonyjgrove/logout
Browse files Browse the repository at this point in the history
Added Logout button
  • Loading branch information
john1jan authored Oct 13, 2017
2 parents 98a5037 + 6fd626f commit 8f031db
Show file tree
Hide file tree
Showing 7 changed files with 546 additions and 219 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,18 @@ If you use the hostedDomain param, make sure to validate the id_token (a JSON we
3. Have your server decode the id_token by using a common JWT library such as [jwt-simple](https://github.com/hokaccha/node-jwt-simple) or by sending a GET request to `https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=YOUR_TOKEN_HERE`
4. The returned decoded token should have an `hd` key equal to the hosted domain you'd like to restrict to.


## Logout
Use GoogleLogout button to logout the user from google.

```js
import GoogleLogout from 'react-google-login';
<GoogleLogout
buttonText="Logout"
onLogoutSuccess={logout}
>
</GoogleLogout>
```
## Parameters

| params | value | default value | description |
Expand Down Expand Up @@ -114,6 +126,8 @@ onFailure callback is called when either initialization or a signin attempt fail
| error | string | Error code |
| details | string | Detailed error description |



Common error codes include:

| error code | description |
Expand Down
46 changes: 29 additions & 17 deletions demo/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom'
// import FontAwesome from 'react-fontawesome';
import GoogleLogin from '../src/index'
// import GoogleLogin from '../dist/google-login'
import { GoogleLogin, GoogleLogout } from '../src/index';

// import GoogleLogin from '../dist/google-login';

const success = response => {
console.log(response)
Expand All @@ -16,43 +17,54 @@ const loading = () => {
console.log('loading')
}

const logout = () => {
console.log('logout');
};


ReactDOM.render(
<div>
<GoogleLogin
clientId="658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com"
scope="https://www.googleapis.com/auth/analytics"
clientId='658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com'
scope='https://www.googleapis.com/auth/analytics'
onSuccess={success}
onFailure={error}
onRequest={loading}
offline={false}
approvalPrompt="force"
responseType="id_token"
isSignedIn
// disabled
// prompt="consent"
// className='button'
// style={{ color: 'red' }}
isSignedIn={true}
// disabled
// prompt="consent"
// className='button'
// style={{ color: 'red' }}
>
<span>Analytics</span>
</GoogleLogin>

<GoogleLogin
clientId="658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com"
scope="https://www.googleapis.com/auth/adwords"
clientId='658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com'
scope='https://www.googleapis.com/auth/adwords'
onSuccess={success}
onFailure={error}
onRequest={loading}
approvalPrompt="force"
responseType="code"
// uxMode="redirect"
// redirectUri="http://google.com"
// disabled
// prompt="consent"
// className='button'
// style={{ color: 'red' }}
// uxMode="redirect"
// redirectUri="http://google.com"
// disabled
// prompt="consent"
// className='button'
// style={{ color: 'red' }}
>
<span>Adwords</span>
</GoogleLogin>

<GoogleLogout
buttonText="Logout"
onLogoutSuccess={logout}
>
</GoogleLogout>
</div>,
document.getElementById('google-login')
)
182 changes: 182 additions & 0 deletions src/GoogleLogin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'

class GoogleLogin extends Component {
constructor(props) {
super(props)
this.signIn = this.signIn.bind(this)
this.state = {
disabled: true
}
}
componentDidMount() {
const { clientId, cookiePolicy, loginHint, hostedDomain, autoLoad, isSignedIn, fetchBasicProfile, redirectUri, discoveryDocs, onFailure, uxMode, scope } = this.props
; ((d, s, id, cb) => {
const element = d.getElementsByTagName(s)[0]
const fjs = element
let js = element
js = d.createElement(s)
js.id = id
js.src = '//apis.google.com/js/client:platform.js'
fjs.parentNode.insertBefore(js, fjs)
js.onload = cb
})(document, 'script', 'google-login', () => {
const params = {
client_id: clientId,
cookie_policy: cookiePolicy,
login_hint: loginHint,
hosted_domain: hostedDomain,
fetch_basic_profile: fetchBasicProfile,
discoveryDocs,
ux_mode: uxMode,
redirect_uri: redirectUri,
scope
}
window.gapi.load('auth2', () => {
this.setState({
disabled: false
})
if (!window.gapi.auth2.getAuthInstance()) {
window.gapi.auth2.init(params).then(
res => {
if (isSignedIn && res.isSignedIn.get()) {
this._handleSigninSuccess(res.currentUser.get())
}
},
err => onFailure(err)
)
}
if (autoLoad) {
this.signIn()
}
})
})
}
signIn(e) {
if (e) {
e.preventDefault() // to prevent submit if used within form
}
if (!this.state.disabled) {
const auth2 = window.gapi.auth2.getAuthInstance()
const { onSuccess, onRequest, onFailure, prompt, responseType } = this.props
const options = {
prompt
}
onRequest()
if (responseType === 'code') {
auth2.grantOfflineAccess(options).then(res => onSuccess(res), err => onFailure(err))
} else {
auth2.signIn(options).then(res => this._handleSigninSuccess(res), err => onFailure(err))
}
}
}
_handleSigninSuccess(res) {
/*
offer renamed response keys to names that match use
*/
const basicProfile = res.getBasicProfile()
const authResponse = res.getAuthResponse()
res.googleId = basicProfile.getId()
res.tokenObj = authResponse
res.tokenId = authResponse.id_token
res.accessToken = authResponse.access_token
res.profileObj = {
googleId: basicProfile.getId(),
imageUrl: basicProfile.getImageUrl(),
email: basicProfile.getEmail(),
name: basicProfile.getName(),
givenName: basicProfile.getGivenName(),
familyName: basicProfile.getFamilyName()
}
this.props.onSuccess(res)
}

render() {
const { tag, type, style, className, disabledStyle, buttonText, children } = this.props
const disabled = this.state.disabled || this.props.disabled
const initialStyle = {
display: 'inline-block',
background: '#d14836',
color: '#fff',
width: 190,
paddingTop: 10,
paddingBottom: 10,
borderRadius: 2,
border: '1px solid transparent',
fontSize: 16,
fontWeight: 'bold',
fontFamily: 'Roboto'
}
const styleProp = (() => {
if (style) {
return style
} else if (className && !style) {
return {}
}
return initialStyle
})()
const defaultStyle = (() => {
if (disabled) {
return Object.assign({}, styleProp, disabledStyle)
}
return styleProp
})()
const googleLoginButton = React.createElement(
tag,
{
onClick: this.signIn,
style: defaultStyle,
type,
disabled,
className
},
children || buttonText
)
return googleLoginButton
}
}

GoogleLogin.propTypes = {
onSuccess: PropTypes.func.isRequired,
onFailure: PropTypes.func.isRequired,
clientId: PropTypes.string.isRequired,
onRequest: PropTypes.func,
buttonText: PropTypes.string,
scope: PropTypes.string,
className: PropTypes.string,
redirectUri: PropTypes.string,
cookiePolicy: PropTypes.string,
loginHint: PropTypes.string,
hostedDomain: PropTypes.string,
children: PropTypes.node,
style: PropTypes.object,
disabledStyle: PropTypes.object,
fetchBasicProfile: PropTypes.bool,
prompt: PropTypes.string,
tag: PropTypes.string,
autoLoad: PropTypes.bool,
disabled: PropTypes.bool,
discoveryDocs: PropTypes.array,
uxMode: PropTypes.string,
isSignedIn: PropTypes.bool,
responseType: PropTypes.string,
type: PropTypes.string
}

GoogleLogin.defaultProps = {
type: 'button',
tag: 'button',
buttonText: 'Login with Google',
scope: 'profile email',
prompt: '',
cookiePolicy: 'single_host_origin',
fetchBasicProfile: true,
isSignedIn: false,
uxMode: 'popup',
disabledStyle: {
opacity: 0.6
},
onRequest: () => { }
}

export default GoogleLogin
101 changes: 101 additions & 0 deletions src/GoogleLogout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'

class GoogleLogout extends Component {
constructor(props) {
super(props)
this.state = {
disabled: true,
}
this.signOut = this.signOut.bind(this)
}
componentDidMount() {
((d, s, id, cb) => {
const element = d.getElementsByTagName(s)[0]
const fjs = element
let js = element
js = d.createElement(s)
js.id = id
js.src = '//apis.google.com/js/client:platform.js'
fjs.parentNode.insertBefore(js, fjs)
js.onload = cb
})(document, 'script', 'google-login', () => {
window.gapi.load('auth2', () => {
this.setState({
disabled: false,
})
})
})
}

signOut() {
const auth2 = window.gapi.auth2.getAuthInstance()
if (auth2 != null) {
auth2.signOut().then(() => {
this.props.onLogoutSuccess()
})
}
}

render() {
const { tag, style, className, disabledStyle, buttonText, children } = this.props
const disabled = this.state.disabled || this.props.disabled
const initialStyle = {
display: 'inline-block',
background: '#d14836',
color: '#fff',
width: 190,
paddingTop: 10,
paddingBottom: 10,
borderRadius: 2,
border: '1px solid transparent',
fontSize: 16,
fontWeight: 'bold',
fontFamily: 'Roboto',
}
const styleProp = (() => {
if (style) {
return style
} else if (className && !style) {
return {}
}
return initialStyle
})()
const defaultStyle = (() => {
if (disabled) {
return Object.assign({}, styleProp, disabledStyle)
}
return styleProp
})()
const googleLoginButton = React.createElement(
tag, {
onClick: this.signOut,
style: defaultStyle,
disabled,
className,
}, children || buttonText
)
return googleLoginButton
}
}

GoogleLogout.propTypes = {
buttonText: PropTypes.string,
className: PropTypes.string,
children: PropTypes.node,
style: PropTypes.object,
disabledStyle: PropTypes.object,
disabled: PropTypes.bool,
}

GoogleLogout.defaultProps = {
tag: 'button',
buttonText: 'Logout',
responseType: 'permission',
disabledStyle: {
opacity: 0.6,
},
onRequest: () => { },
}

export default GoogleLogout
Loading

0 comments on commit 8f031db

Please sign in to comment.