Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
30be85f
Reauthenticate WIP
magrinj Dec 16, 2019
3dc40d1
Fix call on wrong access point
magrinj Dec 20, 2019
3b0cb93
Fix some reauthenticate problems
magrinj Dec 23, 2019
8a01d9c
Add doc and fix types
magrinj Dec 23, 2019
21e22b0
Add typed db schema
vicrac Jan 7, 2020
32a168b
Add types for ordered
vicrac Jan 7, 2020
adcbcd2
chore(deps): bump stringstream
dependabot[bot] Jan 10, 2020
2d0355b
chore(deps): bump mixin-deep in /examples/complete/react-native
dependabot[bot] Jan 10, 2020
540dc29
chore(deps): bump lodash-es in /examples/complete/react-native-firebase
dependabot[bot] Jan 10, 2020
d779f3c
chore(deps): bump lodash in /examples/complete/react-native
dependabot[bot] Jan 10, 2020
2382c62
Fix stale profile listener
illuminist Jan 22, 2020
6636062
fix(auth): remove stale profile listener on empty auth state change -…
prescottprue Jan 23, 2020
19cc871
feat(types): add support for typed db schema - @vicrac - #826
prescottprue Jan 24, 2020
6bf011d
feat(auth): add reauthenticate method from firebase - @magrinj - #812
prescottprue Jan 24, 2020
9122f60
chore(deps): bump lodash from 4.17.11 to 4.17.15 in react-native exam…
prescottprue Jan 24, 2020
ff8f2ca
chore(deps): bump stringstream from 0.0.5 to 0.0.6 in react-native-fi…
prescottprue Jan 24, 2020
1d03e29
chore(deps): bump mixin-deep from 1.3.1 to 1.3.2 in react-native exam…
prescottprue Jan 24, 2020
d97fbfa
chore(deps): bump diff in /examples/complete/react-native-firebase
dependabot[bot] Jan 24, 2020
849094e
chore(deps): bump lodash-es from 4.17.4 to 4.17.15 in react-native-fi…
prescottprue Jan 24, 2020
0bbdc86
Merge branch 'master' into v3.1.0
Jan 24, 2020
f416be8
chore(deps): bump diff from 3.3.0 to 3.5.0 in react-native-firebase e…
prescottprue Jan 24, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 34 additions & 3 deletions docs/auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ If you need access to methods that are not available at the top level, you can a

For examples of how to use this API, checkout the [auth recipes section](/docs/recipes/auth.html).

## login(credentials)
## login(credentials) and reauthenticate(credentials)

##### Parameters
##### Parameters for login

* `credentials` ([**Object**][object-url])
* [**Object**][object-url] - cases:
* email and password (runs `ref.authWithPassword(credentials)`) :
* - email and password (runs `ref.authWithPassword(credentials)`) :
```js
{
email: String,
Expand Down Expand Up @@ -78,6 +78,33 @@ For examples of how to use this API, checkout the [auth recipes section](/docs/r
}
```

##### Parameters for reauthenticate

* `credentials` ([**Object**][object-url])
* [**Object**][object-url] - cases:
* provider (runs `ref.reauthenticateWithPopup(provider)` or `ref.reauthenticateWithRedirect(provider)`) :
```js
{
provider: "facebook | google | twitter",
type: "popup | redirect", // popup is default
scopes: Array // email is default
}
```
* credential (runs `ref.reauthenticateWithCredential(credential)`) :
```js
{
credential: firebase.auth.AuthCredential // created using specific provider
}
```
The credential parameter is a firebase.auth.AuthCredential specific to the provider (i.e. `firebase.auth.GoogleAuthProvider.credential(null)`). For more details [please view the Firebase API reference](https://firebase.google.com/docs/reference/js/firebase.auth.GoogleAuthProvider#methods)
* phone number (runs `ref.reauthenticateWithPhoneNumber(phoneNumber, applicationVerifier)`). Automatic profile creation is enabled by default if you are using the `userProfile` config option. `updateProfileOnLogin` config option can be set to `false` in order to prevent this behavior.
```js
{
phoneNumber: String,
applicationVerifier: firebase.auth.ApplicationVerifier
}
```

##### Returns

[**Promise**][promise-url] that resolves with the response from firebase's login method (an [**Object**][object-url]). `credential` property is also included if using oAuth provider.
Expand Down Expand Up @@ -121,6 +148,10 @@ firebase.login({
firebase.login({
credential: firebase.auth.GoogleAuthProvider.credential(null, 'some access token')
})
// or using reauthenticate
firebase.reauthenticate({
credential: firebase.auth.GoogleAuthProvider.credential(null, 'some access token')
})
```

*Token*
Expand Down
67 changes: 66 additions & 1 deletion src/actions/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { populate } from '../helpers'
import { isString } from '../utils'
import {
getLoginMethodAndParams,
getReauthenticateMethodAndParams,
updateProfileOnRTDB,
updateProfileOnFirestore,
setupPresence
Expand All @@ -12,14 +13,17 @@ import { promisesForPopulate, getPopulateObjs } from '../utils/populate'

/**
* Dispatch login error action
*
* @param {Function} dispatch - Action dispatch function
* @param {object} authError - Error object
* @param {object} params - Supplement action params
* @returns {any} Return of action dispatch
* @private
*/
function dispatchLoginError(dispatch, authError) {
function dispatchLoginError(dispatch, authError, params = {}) {
return dispatch({
type: actionTypes.LOGIN_ERROR,
...params,
authError
})
}
Expand Down Expand Up @@ -584,6 +588,67 @@ export const login = (dispatch, firebase, credentials) => {
})
}

/**
* Reauthenticate with errors dispatched
* @param {Function} dispatch - Action dispatch function
* @param {object} firebase - Internal firebase object
* @param {object} credentials - Login credentials
* @param {object} credentials.provider - Provider name such as google, twitter (only needed for 3rd party provider login)
* @param {object} credentials.type - Popup or redirect (only needed for 3rd party provider login)
* @param {firebase.auth.AuthCredential} credentials.credential - Custom or provider token
* @param {Array|string} credentials.scopes - Scopes to add to provider (i.e. email)
* @returns {Promise} Resolves after user is logged in
* @private
*/
export const reauthenticate = (dispatch, firebase, credentials) => {
const { method, params } = getReauthenticateMethodAndParams(
firebase,
credentials
)

return firebase
.auth()
.currentUser[method](...params)
.then(userData => {
// Handle null response from getRedirectResult before redirect has happened
if (!userData) return Promise.resolve(null)

if (method === 'reauthenticateWithPhoneNumber') {
// Modify confirm method to include profile creation
return {
...userData,
confirm: code =>
// Call original confirm
userData.confirm(code).then(({ user, additionalUserInfo }) =>
createUserProfile(dispatch, firebase, user, {
phoneNumber: user.providerData[0].phoneNumber,
providerData: user.providerData
}).then(profile => ({ profile, user, additionalUserInfo }))
)
}
}

// Create profile when logging in with external provider
const user = userData.user || userData

return createUserProfile(
dispatch,
firebase,
user,
credentials.profile || {
email: user.email,
displayName: user.providerData[0].displayName || user.email,
avatarUrl: user.providerData[0].photoURL,
providerData: user.providerData
}
).then(profile => ({ profile, ...userData }))
})
.catch(err => {
dispatchLoginError(dispatch, err, { reauthenticate: true })
return Promise.reject(err)
})
}

/**
* Logout of firebase and dispatch logout event
* @param {Function} dispatch - Action dispatch function
Expand Down
19 changes: 19 additions & 0 deletions src/createFirebaseInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ export default function createFirebaseInstance(firebase, configs, dispatch) {
* [auth section of the docs](https://react-redux-firebase.com/docs/auth.html) or the
* [auth recipes section](https://react-redux-firebase.com/docs/recipes/auth.html).
* @param {object} credentials - Credentials for authenticating
* @param {object} credential - Credential object for authenticating
* @param {string} credentials.provider - External provider (google |
* facebook | twitter)
* @param {string} credentials.type - Type of external authentication
Expand All @@ -396,6 +397,23 @@ export default function createFirebaseInstance(firebase, configs, dispatch) {
const login = credentials =>
authActions.login(dispatch, firebase, credentials)

/**
* Reauthenticate user into Firebase. For examples, visit the
* [auth section of the docs](https://react-redux-firebase.com/docs/auth.html) or the
* [auth recipes section](https://react-redux-firebase.com/docs/recipes/auth.html).
* @param {object} credentials - Credentials for authenticating
* @param {object} credential - Credential object for authenticating
* @param {string} credentials.provider - External provider (google |
* facebook | twitter)
* @param {string} credentials.type - Type of external authentication
* (popup | redirect) (only used with provider)
* @returns {Promise} Containing user's auth data
* @see https://react-redux-firebase.com/docs/auth.html#logincredentials
* @see https://react-redux-firebase.com/docs/api/firebaseInstance.html#login
*/
const reauthenticate = credentials =>
authActions.reauthenticate(dispatch, firebase, credentials)

/**
* Logs user into Firebase using external. For examples, visit the
* [auth section](/docs/recipes/auth.md)
Expand Down Expand Up @@ -571,6 +589,7 @@ export default function createFirebaseInstance(firebase, configs, dispatch) {
update,
updateWithMeta,
login,
reauthenticate,
handleRedirectResult,
logout,
updateAuth,
Expand Down
4 changes: 4 additions & 0 deletions src/reducers.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ export function authReducer(
case LOGIN_ERROR:
case AUTH_EMPTY_CHANGE:
case LOGOUT:
// If it's reauthenticate keep user datas
if (action.reauthenticate) {
return preserveValuesFromState(state, true, {})
}
// Support keeping data when logging out
if (action.preserve && action.preserve.auth) {
return preserveValuesFromState(state, action.preserve.auth, {
Expand Down
63 changes: 63 additions & 0 deletions src/utils/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,69 @@ export function getLoginMethodAndParams(firebase, credentials) {
return { method: 'signInWithEmailAndPassword', params: [email, password] }
}

/**
* Get correct reauthenticate method and params order based on provided
* credentials
* @param {object} firebase - Internal firebase object
* @param {object} credentials - Login credentials
* @param {string} credentials.provider - Provider name such as google, twitter
* (only needed for 3rd party provider login)
* @param {string} credentials.type - Popup or redirect (only needed for 3rd
* party provider login)
* @param {firebase.auth.AuthCredential} credentials.credential - Custom or
* provider token
* @param {Array|string} credentials.scopes - Scopes to add to provider
* (i.e. email)
* @returns {object} Method and params for calling login
* @private
*/
export function getReauthenticateMethodAndParams(firebase, credentials) {
const {
provider,
type,
scopes,
phoneNumber,
applicationVerifier,
credential
} = credentials
// Credential Auth
if (credential) {
// Attempt to use signInAndRetrieveDataWithCredential if it exists (see #467 for more info)
const credentialAuth = firebase.auth()
.reauthenticateAndRetrieveDataWithCredential

if (credentialAuth) {
return {
method: 'reauthenticateAndRetrieveDataWithCredential',
params: [credential]
}
}
return { method: 'reauthenticateWithCredential', params: [credential] }
}

// Provider Auth
if (provider) {
// Verify providerName is valid
if (supportedAuthProviders.indexOf(provider.toLowerCase()) === -1) {
throw new Error(`${provider} is not a valid Auth Provider`)
}
const authProvider = createAuthProvider(firebase, provider, scopes)
if (type === 'popup') {
return { method: 'reauthenticateWithPopup', params: [authProvider] }
}
return { method: 'reauthenticateWithRedirect', params: [authProvider] }
}

// Phone Number Auth
if (!applicationVerifier) {
throw new Error('Application verifier is required for phone authentication')
}
return {
method: 'reauthenticateWithPhoneNumber',
params: [phoneNumber, applicationVerifier]
}
}

/**
* Returns a promise that completes when Firebase Auth is ready in the given
* store using react-redux-firebase.
Expand Down