From 1eee722978cd8683b09e21533c09e44b25f1b742 Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Sat, 24 Sep 2022 22:44:04 +0200 Subject: [PATCH 01/11] feat(auth): Add support for OpenID Connect provider --- packages/auth/ios/RNFBAuth/RNFBAuthModule.m | 4 +++ packages/auth/lib/providers/OIDCProvider.js | 36 +++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 packages/auth/lib/providers/OIDCProvider.js diff --git a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m index 4900760e7d..7025b96d49 100644 --- a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m +++ b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m @@ -980,6 +980,10 @@ - (FIRAuthCredential *)getCredentialForProvider:(NSString *)provider credential = [FIROAuthProvider credentialWithProviderID:@"oauth" IDToken:authToken accessToken:authTokenSecret]; + } else if ([provider hasPrefix:@"oidc."] ) { + credential = [FIROAuthProvider credentialWithProviderID:provider + IDToken:authToken + rawNonce:nil]; } else { DLog(@"Provider not yet handled: %@", provider); } diff --git a/packages/auth/lib/providers/OIDCProvider.js b/packages/auth/lib/providers/OIDCProvider.js new file mode 100644 index 0000000000..b96d601134 --- /dev/null +++ b/packages/auth/lib/providers/OIDCProvider.js @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016-present Invertase Limited & Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this library except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const providerId = 'oidc.'; + +export default class OAuthProvider { + constructor() { + throw new Error('`new OAuthProvider()` is not supported on the native Firebase SDKs.'); + } + + static get PROVIDER_ID() { + return providerId; + } + + static credential(oidcSuffix, idToken, accessToken) { + return { + token: idToken, + secret: accessToken, + providerId: providerId + oidcSuffix, + }; + } +} From 3ff0c2e5f126addaf9cefa04692e9e11ce0c706d Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Sat, 24 Sep 2022 23:05:52 +0200 Subject: [PATCH 02/11] Added OIDC to imports. --- packages/auth/lib/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/auth/lib/index.js b/packages/auth/lib/index.js index 4e57952b8e..e1f968c6b5 100644 --- a/packages/auth/lib/index.js +++ b/packages/auth/lib/index.js @@ -34,6 +34,7 @@ import FacebookAuthProvider from './providers/FacebookAuthProvider'; import GithubAuthProvider from './providers/GithubAuthProvider'; import GoogleAuthProvider from './providers/GoogleAuthProvider'; import OAuthProvider from './providers/OAuthProvider'; +import OIDCProvider from './providers/OIDCProvider'; import PhoneAuthProvider from './providers/PhoneAuthProvider'; import TwitterAuthProvider from './providers/TwitterAuthProvider'; import AppleAuthProvider from './providers/AppleAuthProvider'; @@ -50,6 +51,7 @@ const statics = { TwitterAuthProvider, FacebookAuthProvider, OAuthProvider, + OIDCProvider, PhoneAuthState: { CODE_SENT: 'sent', AUTO_VERIFY_TIMEOUT: 'timeout', From 4d8eed5a7737e11c0308f208908516da8547d0a0 Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Sun, 25 Sep 2022 21:38:46 +0200 Subject: [PATCH 03/11] Fixed linting errors. --- packages/auth/ios/RNFBAuth/RNFBAuthModule.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m index 7025b96d49..6d7166fafb 100644 --- a/packages/auth/ios/RNFBAuth/RNFBAuthModule.m +++ b/packages/auth/ios/RNFBAuth/RNFBAuthModule.m @@ -980,7 +980,7 @@ - (FIRAuthCredential *)getCredentialForProvider:(NSString *)provider credential = [FIROAuthProvider credentialWithProviderID:@"oauth" IDToken:authToken accessToken:authTokenSecret]; - } else if ([provider hasPrefix:@"oidc."] ) { + } else if ([provider hasPrefix:@"oidc."]) { credential = [FIROAuthProvider credentialWithProviderID:provider IDToken:authToken rawNonce:nil]; From 0e33db77473080a9526f9df07e8d4fe263a48af8 Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Tue, 27 Sep 2022 23:00:54 +0200 Subject: [PATCH 04/11] Added OIDC support for Android. Added OIDC e2e tests. Renamed OIDCProvider to OIDCAuthProvider to be more consistent with the naming of other providers. --- .../auth/ReactNativeFirebaseAuthModule.java | 4 +++ packages/auth/e2e/provider.e2e.js | 28 +++++++++++++++++++ packages/auth/lib/index.js | 4 +-- .../{OIDCProvider.js => OIDCAuthProvider.js} | 4 +-- 4 files changed, 36 insertions(+), 4 deletions(-) rename packages/auth/lib/providers/{OIDCProvider.js => OIDCAuthProvider.js} (87%) diff --git a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java index acfb6983ed..e1def8f89c 100644 --- a/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java +++ b/packages/auth/android/src/main/java/io/invertase/firebase/auth/ReactNativeFirebaseAuthModule.java @@ -1306,6 +1306,10 @@ private void reauthenticateWithCredential( /** Returns an instance of AuthCredential for the specified provider */ private AuthCredential getCredentialForProvider( String provider, String authToken, String authSecret) { + if (provider.startsWith("oidc.")) { + return OAuthProvider.newCredentialBuilder(provider).setIdToken(authToken).build(); + } + switch (provider) { case "facebook.com": return FacebookAuthProvider.getCredential(authToken); diff --git a/packages/auth/e2e/provider.e2e.js b/packages/auth/e2e/provider.e2e.js index 90463b35b2..1475eb5675 100644 --- a/packages/auth/e2e/provider.e2e.js +++ b/packages/auth/e2e/provider.e2e.js @@ -226,4 +226,32 @@ describe('auth() -> Providers', function () { }); }); }); + + describe('OIDCAuthProvider', function () { + describe('constructor', function () { + it('should throw an unsupported error', function () { + (() => new firebase.auth.OIDCAuthProvider()).should.throw( + '`new OIDCAuthProvider()` is not supported on the native Firebase SDKs.', + ); + }); + }); + + describe('credential', function () { + it('should return a credential object', function () { + const token = '123456'; + const secret = '654321'; + const providerSuffix = 'sample-provider'; + const credential = firebase.auth.OIDCAuthProvider.credential(providerSuffix, token, secret); + credential.providerId.should.equal('oidc.' + providerSuffix); + credential.token.should.equal(token); + credential.secret.should.equal(secret); + }); + }); + + describe('PROVIDER_ID', function () { + it('should return oidc.', function () { + firebase.auth.OIDCAuthProvider.PROVIDER_ID.should.equal('oidc.'); + }); + }); + }); }); diff --git a/packages/auth/lib/index.js b/packages/auth/lib/index.js index e1f968c6b5..99d7592db4 100644 --- a/packages/auth/lib/index.js +++ b/packages/auth/lib/index.js @@ -34,7 +34,7 @@ import FacebookAuthProvider from './providers/FacebookAuthProvider'; import GithubAuthProvider from './providers/GithubAuthProvider'; import GoogleAuthProvider from './providers/GoogleAuthProvider'; import OAuthProvider from './providers/OAuthProvider'; -import OIDCProvider from './providers/OIDCProvider'; +import OIDCAuthProvider from './providers/OIDCAuthProvider'; import PhoneAuthProvider from './providers/PhoneAuthProvider'; import TwitterAuthProvider from './providers/TwitterAuthProvider'; import AppleAuthProvider from './providers/AppleAuthProvider'; @@ -51,7 +51,7 @@ const statics = { TwitterAuthProvider, FacebookAuthProvider, OAuthProvider, - OIDCProvider, + OIDCAuthProvider, PhoneAuthState: { CODE_SENT: 'sent', AUTO_VERIFY_TIMEOUT: 'timeout', diff --git a/packages/auth/lib/providers/OIDCProvider.js b/packages/auth/lib/providers/OIDCAuthProvider.js similarity index 87% rename from packages/auth/lib/providers/OIDCProvider.js rename to packages/auth/lib/providers/OIDCAuthProvider.js index b96d601134..d262a29548 100644 --- a/packages/auth/lib/providers/OIDCProvider.js +++ b/packages/auth/lib/providers/OIDCAuthProvider.js @@ -17,9 +17,9 @@ const providerId = 'oidc.'; -export default class OAuthProvider { +export default class OIDCAuthProvider { constructor() { - throw new Error('`new OAuthProvider()` is not supported on the native Firebase SDKs.'); + throw new Error('`new OIDCAuthProvider()` is not supported on the native Firebase SDKs.'); } static get PROVIDER_ID() { From 6cfadd449db7570d4dc067215b7e5c6543ec03a9 Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Tue, 20 Dec 2022 20:54:42 +0100 Subject: [PATCH 05/11] Added documentation for oidc provider. --- docs/auth/multi-factor-auth.md | 2 +- docs/auth/oidc-auth.md | 61 ++++++++++++++++++++++++++++++++++ docs/auth/phone-auth.md | 2 +- 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 docs/auth/oidc-auth.md diff --git a/docs/auth/multi-factor-auth.md b/docs/auth/multi-factor-auth.md index efc94a7418..18d91540dc 100644 --- a/docs/auth/multi-factor-auth.md +++ b/docs/auth/multi-factor-auth.md @@ -2,7 +2,7 @@ title: Multi-factor Auth description: Increase security by adding Multi-factor authentication to your app. next: /firestore/usage -previous: /auth/phone-auth +previous: /auth/oidc-auth --- # iOS Setup diff --git a/docs/auth/oidc-auth.md b/docs/auth/oidc-auth.md new file mode 100644 index 0000000000..280d456307 --- /dev/null +++ b/docs/auth/oidc-auth.md @@ -0,0 +1,61 @@ +--- +title: OpenID Connect Authentication +description: Sign-in users using OIDC. +next: /auth/multi-factor-auth +previous: /auth/phone-auth +--- + +React Native Firebase provides supports integrating with OpenID Connect providers. The authentication with these +different providers is left to you to implement due to the various implementations and flows possible. + +Here we will demonstrate a minimal example of how you could do this using the package [react-native-app-auth](https://github.com/FormidableLabs/react-native-app-auth) to authenticate with the provider. Then after we have authenticated with the provider, we use the ID Token from the provider to authenticate with `react-native-firebase`. But you have to handle the flow to get the ID token and you should do things like logging the user out from the provider when they logout or revoke the token. Again this all depends on the provider, your flow and your use-case. + +To get started with OIDC authentication you generally need to do the following: + +1. Setup or get the configuration from the provider you want to use +2. Add the provider in the firebase console +3. Authenticate in the app using `react-native-app-auth` and `react-native-firebase` + +## 1. Setup or get the configuration from the provider you want to use + +As stated before, this will vary a lot from provider to provider and your use-case. You need to find and look the documentation for the provider you want to use. +You can see examples of "Tested OpenID providers" from [react-native-app-auth here](https://github.com/FormidableLabs/react-native-app-auth#tested-openid-providers) and how you do this will depend on what provider you want to use. But you need to complete the setup or configuration of the provider you want to use before you continue here. + +## 2. Add the provider in the Firebase console + +1. Firebase console in the project you want to add OpenID Connect to +2. Authentication +3. Sign-in method +4. If you have added "Sign-in providers" already, click "Add new provider" +5. Under "Custom providers" choose "OpenID Connect" +6. Toggle on the Enabled at the top to the right of "Open ID Connect" +7. Fill out the details like: "Name", "Client ID", "Issuer (URL)" and "Client secret". These values have to correspond to the OpenID Connect provider you want to use. +8. Note down the Provider ID below name, if you type in "azure_test" in the name field. Notice how it says below the field: "Provider ID: oidc.azure_test" so this value will be prepended with "oidc." We will use this later when authenticating the user. + +## 3. Authenticate in the app using `react-native-app-auth` and `react-native-firebase` + +The example below demonstrates how you could setup such a flow within your own application: + +```jsx +import auth from '@react-native-firebase/auth'; +import { authorize } from 'react-native-app-auth'; + +// using react-native-app-auth to get oauth token from Azure AD +const config = { + issuer: 'https://login.microsoftonline.com/XXX/v2.0', + clientId: 'XXXX', + redirectUrl: 'msauth.your.bundle.id://auth/', + scopes: ['openid', 'profile', 'email', 'offline_access'], + useNonce: false, +}; + +// Log in to get an authentication token +const authState = await authorize(config); + +const credential = auth.OIDCProvider.credential( + 'azure_test', // this is the "Provider ID" value from the firebase console + authState.idToken, +); + +await auth().signInWithCredential(credential); +``` diff --git a/docs/auth/phone-auth.md b/docs/auth/phone-auth.md index 4ff7f97298..26da1d7541 100644 --- a/docs/auth/phone-auth.md +++ b/docs/auth/phone-auth.md @@ -1,7 +1,7 @@ --- title: Phone Authentication description: Sign-in users with their phone number. -next: /auth/multi-factor-auth +next: /auth/oidc-auth previous: /auth/social-auth --- From 63bcdc17a8eba354fe99811363b9bb5fe3d7166c Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Tue, 20 Dec 2022 21:03:37 +0100 Subject: [PATCH 06/11] Updated description and added oidc-auth to the sidebar. --- docs/auth/oidc-auth.md | 2 +- docs/sidebar.yaml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/auth/oidc-auth.md b/docs/auth/oidc-auth.md index 280d456307..2e6b9067a3 100644 --- a/docs/auth/oidc-auth.md +++ b/docs/auth/oidc-auth.md @@ -1,6 +1,6 @@ --- title: OpenID Connect Authentication -description: Sign-in users using OIDC. +description: Sign-in users using OpenID Connect. next: /auth/multi-factor-auth previous: /auth/phone-auth --- diff --git a/docs/sidebar.yaml b/docs/sidebar.yaml index 09e7eec090..b349815ea6 100644 --- a/docs/sidebar.yaml +++ b/docs/sidebar.yaml @@ -38,6 +38,8 @@ - '/auth/social-auth' - - Phone Auth - '/auth/phone-auth' + - - OpenID Connect Auth + - '/auth/oidc-auth' - - Multi-factor Auth - '/auth/multi-factor-auth' - '//static.invertase.io/assets/firebase/authentication.svg' From d2bd6db77328cc3e477fc62a89fc9cdf0b737c5c Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Tue, 20 Dec 2022 21:05:48 +0100 Subject: [PATCH 07/11] Updated header due to styling making it confusing. --- docs/auth/oidc-auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth/oidc-auth.md b/docs/auth/oidc-auth.md index 2e6b9067a3..86cceaf128 100644 --- a/docs/auth/oidc-auth.md +++ b/docs/auth/oidc-auth.md @@ -32,7 +32,7 @@ You can see examples of "Tested OpenID providers" from [react-native-app-auth he 7. Fill out the details like: "Name", "Client ID", "Issuer (URL)" and "Client secret". These values have to correspond to the OpenID Connect provider you want to use. 8. Note down the Provider ID below name, if you type in "azure_test" in the name field. Notice how it says below the field: "Provider ID: oidc.azure_test" so this value will be prepended with "oidc." We will use this later when authenticating the user. -## 3. Authenticate in the app using `react-native-app-auth` and `react-native-firebase` +## 3. Authenticate in the app using **react-native-app-auth** and **react-native-firebase** The example below demonstrates how you could setup such a flow within your own application: From 85fe346657f824cf661efe957d604f9b03b344c9 Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Tue, 20 Dec 2022 21:19:07 +0100 Subject: [PATCH 08/11] Updated header again. --- docs/auth/oidc-auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth/oidc-auth.md b/docs/auth/oidc-auth.md index 86cceaf128..5aaa05c7d3 100644 --- a/docs/auth/oidc-auth.md +++ b/docs/auth/oidc-auth.md @@ -32,7 +32,7 @@ You can see examples of "Tested OpenID providers" from [react-native-app-auth he 7. Fill out the details like: "Name", "Client ID", "Issuer (URL)" and "Client secret". These values have to correspond to the OpenID Connect provider you want to use. 8. Note down the Provider ID below name, if you type in "azure_test" in the name field. Notice how it says below the field: "Provider ID: oidc.azure_test" so this value will be prepended with "oidc." We will use this later when authenticating the user. -## 3. Authenticate in the app using **react-native-app-auth** and **react-native-firebase** +## 3. Authenticate in the app using "react-native-app-auth" and "react-native-firebase" The example below demonstrates how you could setup such a flow within your own application: From 658929d565e0684b774ee94c2c93cce4d08b765d Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Wed, 21 Dec 2022 01:07:00 +0100 Subject: [PATCH 09/11] Clarified parts of the docs. --- docs/auth/oidc-auth.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/auth/oidc-auth.md b/docs/auth/oidc-auth.md index 5aaa05c7d3..060742ba42 100644 --- a/docs/auth/oidc-auth.md +++ b/docs/auth/oidc-auth.md @@ -10,7 +10,9 @@ different providers is left to you to implement due to the various implementatio Here we will demonstrate a minimal example of how you could do this using the package [react-native-app-auth](https://github.com/FormidableLabs/react-native-app-auth) to authenticate with the provider. Then after we have authenticated with the provider, we use the ID Token from the provider to authenticate with `react-native-firebase`. But you have to handle the flow to get the ID token and you should do things like logging the user out from the provider when they logout or revoke the token. Again this all depends on the provider, your flow and your use-case. -To get started with OIDC authentication you generally need to do the following: +# Getting started + +To get started with OpenID Connect authentication you need to do the following: 1. Setup or get the configuration from the provider you want to use 2. Add the provider in the firebase console @@ -18,11 +20,14 @@ To get started with OIDC authentication you generally need to do the following: ## 1. Setup or get the configuration from the provider you want to use -As stated before, this will vary a lot from provider to provider and your use-case. You need to find and look the documentation for the provider you want to use. +As stated before, this will vary a lot from provider to provider and your use-case. You need to find and look the documentation for the provider you want to use and follow that documentation to setup a working provider. You can see examples of "Tested OpenID providers" from [react-native-app-auth here](https://github.com/FormidableLabs/react-native-app-auth#tested-openid-providers) and how you do this will depend on what provider you want to use. But you need to complete the setup or configuration of the provider you want to use before you continue here. ## 2. Add the provider in the Firebase console +Doing the steps below will allow you to add the provider to the Firebase project. +If the provider is not added there, you won't be able to use the `signInWithCredential` method, since Firebase will not be able to use the credential if the provider does not exist in the project. + 1. Firebase console in the project you want to add OpenID Connect to 2. Authentication 3. Sign-in method @@ -34,6 +39,8 @@ You can see examples of "Tested OpenID providers" from [react-native-app-auth he ## 3. Authenticate in the app using "react-native-app-auth" and "react-native-firebase" +Before you use `react-native-app-auth` you have to complete the setup in their [docs](https://github.com/FormidableLabs/react-native-app-auth#getting-started). + The example below demonstrates how you could setup such a flow within your own application: ```jsx From bf2e25e3fa64da43f3b78ac25fb2afee6f260665 Mon Sep 17 00:00:00 2001 From: Jon Babsvik Date: Wed, 18 Jan 2023 22:16:57 +0100 Subject: [PATCH 10/11] Updated to OIDCAuthProvider in the docs. --- docs/auth/oidc-auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth/oidc-auth.md b/docs/auth/oidc-auth.md index 060742ba42..c258e29b2e 100644 --- a/docs/auth/oidc-auth.md +++ b/docs/auth/oidc-auth.md @@ -59,7 +59,7 @@ const config = { // Log in to get an authentication token const authState = await authorize(config); -const credential = auth.OIDCProvider.credential( +const credential = auth.OIDCAuthProvider.credential( 'azure_test', // this is the "Provider ID" value from the firebase console authState.idToken, ); From c4c3ce8050987f4b27013c29d70422e006b5ccc8 Mon Sep 17 00:00:00 2001 From: Mike Hardy Date: Fri, 27 Jan 2023 12:19:35 -0500 Subject: [PATCH 11/11] style(spellcheck): add react-native-app-auth + prepended --- .spellcheck.dict.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.spellcheck.dict.txt b/.spellcheck.dict.txt index de6e4a42f3..a4869316b5 100644 --- a/.spellcheck.dict.txt +++ b/.spellcheck.dict.txt @@ -134,10 +134,12 @@ pre-release pre-rendered preflight preloaded +prepended programmatically PRs PubSub qa +react-native-app-auth react-native-firebase react-native-mlkit realtime