Skip to content

Commit a084edf

Browse files
authored
Full rewrite with FirebaseUI (#180)
v4
1 parent 7fc2859 commit a084edf

File tree

275 files changed

+26973
-2232
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

275 files changed

+26973
-2232
lines changed

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[*.cs]
2+
3+
# CS1591: Missing XML comment for publicly visible type or member
4+
dotnet_diagnostic.CS1591.severity = silent

.github/workflows/dotnetcore.yml

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
name: build
2+
3+
on:
4+
push:
5+
branches: '**'
6+
tags: 'v*.*.*'
7+
pull_request:
8+
9+
jobs:
10+
build:
11+
runs-on: windows-latest
12+
steps:
13+
- uses: actions/checkout@v3
14+
- name: Setup .NET Core
15+
uses: actions/setup-dotnet@v3
16+
with:
17+
dotnet-version: 6
18+
- name: Setup MSBuild
19+
uses: microsoft/[email protected]
20+
- name: Build
21+
run: .\build\build-libs.ps1
22+
env:
23+
DOTNET_CLI_TELEMETRY_OPTOUT: 1
24+
- name: Run Tests
25+
env:
26+
FIREBASE_AUTH_TEST_API_KEY: ${{ secrets.FIREBASE_AUTH_TEST_API_KEY }}
27+
FIREBASE_AUTH_TEST_DOMAIN: ${{ secrets.FIREBASE_AUTH_TEST_DOMAIN }}
28+
run: .\build\run-tests.ps1
29+
pack:
30+
runs-on: windows-latest
31+
needs: build
32+
if: github.event_name == 'push'
33+
steps:
34+
- uses: actions/checkout@v3
35+
- name: Setup .NET Core
36+
uses: actions/setup-dotnet@v3
37+
with:
38+
dotnet-version: 6
39+
- name: Setup MSBuild
40+
uses: microsoft/[email protected]
41+
- name: Pack preview
42+
if: startsWith(github.ref, 'refs/tags/') == false
43+
run: .\build\run-pack.ps1 -preview
44+
env:
45+
DOTNET_CLI_TELEMETRY_OPTOUT: 1
46+
- name: Pack from tag
47+
if: startsWith(github.ref, 'refs/tags/')
48+
run: .\build\run-pack.ps1
49+
env:
50+
DOTNET_CLI_TELEMETRY_OPTOUT: 1
51+
- uses: actions/upload-artifact@v3
52+
with:
53+
name: artifacts
54+
path: ./artifacts
55+
publish:
56+
runs-on: ubuntu-latest
57+
needs: pack
58+
if: github.event_name == 'push'
59+
steps:
60+
- name: Setup .NET Core
61+
uses: actions/setup-dotnet@v3
62+
with:
63+
dotnet-version: 6
64+
- uses: actions/download-artifact@v3
65+
with:
66+
name: artifacts
67+
path: ./artifacts
68+
- name: Publish to Feedz.io
69+
if: startsWith(github.ref, 'refs/tags/') == false
70+
run: dotnet nuget push ./artifacts/**/*.nupkg --source https://f.feedz.io/step-up-labs/firebase/nuget/index.json --api-key ${{secrets.FEEDZ_TOKEN}}
71+
- name: Publish to Nuget.org
72+
if: startsWith(github.ref, 'refs/tags/')
73+
run: dotnet nuget push ./artifacts/**/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.NUGET_TOKEN}}

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## Ignore Visual Studio temporary files, build results, and
22
## files generated by popular Visual Studio add-ons.
3+
4+
build/temp
5+
samples/UWP/BundleArtifacts
36

47
# User-specific files
58
*.suo
@@ -17,7 +20,6 @@
1720
[Rr]eleases/
1821
x64/
1922
x86/
20-
build/
2123
bld/
2224
[Bb]in/
2325
[Oo]bj/

Firebase.Auth.sln

Lines changed: 262 additions & 0 deletions
Large diffs are not rendered by default.

LICENSE renamed to LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
The MIT License (MIT)
22

3-
Copyright (c) 2016 Step Up Labs
3+
Copyright (c) 2019 Step Up Labs
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 203 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,223 @@
11
# FirebaseAuthentication.net
2-
[![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/rwmdgqcb7is2clqp?svg=true)](https://ci.appveyor.com/project/bezysoftware/firebase-authentication-dotnet)
2+
[![build](https://github.com/step-up-labs/firebase-authentication-dotnet/workflows/build/badge.svg)](https://github.com/step-up-labs/firebase-authentication-dotnet/actions)
3+
[![latest version](https://img.shields.io/nuget/v/FirebaseAuthentication.net)](https://www.nuget.org/packages/FirebaseAuthentication.net)
4+
[![feedz.io](https://img.shields.io/badge/endpoint.svg?url=https%3A%2F%2Ff.feedz.io%2Fstep-up-labs%2Ffirebase%2Fshield%2FFirebaseAuthentication.net%2Flatest)](https://f.feedz.io/step-up-labs/firebase/packages/FirebaseAuthentication.net/latest/download)
35

4-
❗ New version of this library with **FirebaseUI** support is being developed in [v4 branch](https://github.com/step-up-labs/firebase-authentication-dotnet/tree/feature/v4)
6+
FirebaseAuthentication.net is an unofficial C# implementation of [Firebase Authentication](https://firebase.google.com/docs/auth)
7+
and [FirebaseUI](https://firebase.google.com/docs/auth).
58

6-
Firebase authentication library. It can generate Firebase auth token based on given OAuth token (issued by Google, Facebook...). This Firebase token can then be used with REST queries against Firebase Database endpoints. See [FirebaseDatabase.net](https://github.com/step-up-labs/firebase-database-dotnet) for a C# library wrapping the Firebase Database REST queries.
9+
The libraries provide a drop-in auth solution that handles the flows for signing in users with email addresses and passwords, Identity Provider Sign In including Google, Facebook, GitHub, Twitter, Apple, Microsoft and anonymous sign-in.
10+
11+
The solution consists of 4 libraries - a base one and 3 platform specific ones:
12+
* FirebaseAuthentication<strong>.net</strong> targets [.NET Standard 2.0](https://github.com/dotnet/standard/blob/master/docs/versions.md)
13+
* FirebaseAuthentication<strong>.WPF</strong> targets [WPF on .NET 6](https://github.com/dotnet/wpf)
14+
* FirebaseAuthentication<strong>.UWP</strong> targets [UWP with min version 19041](https://docs.microsoft.com/en-us/windows/uwp/updates-and-versions/choose-a-uwp-version)
15+
* FirebaseAuthentication<strong>.Xamarin</strong> targets Xamarin.Forms (*TODO*)
716

817
## Installation
9-
```csharp
10-
// Install release version
11-
Install-Package FirebaseAuthentication.net
18+
19+
Either via Visual Studio [Nuget](https://www.nuget.org/packages/FirebaseAuthentication.net) package manager, or from command line:
20+
21+
```powershell
22+
# base package
23+
dotnet add package FirebaseAuthentication.net
24+
25+
# Platform specific FirebaseUI (has dependency on base package)
26+
dotnet add package FirebaseAuthentication.WPF
27+
dotnet add package FirebaseAuthentication.UWP
28+
dotnet add package FirebaseAuthentication.Xamarin
1229
```
1330

14-
## Supported frameworks
15-
* .NET Standard 1.1 - see https://github.com/dotnet/standard/blob/master/docs/versions.md for compatibility matrix
31+
Use the `--version` option to specify a [preview version](https://www.nuget.org/packages/FirebaseAuthentication.net/absoluteLatest) to install.
1632

17-
## Supported scenarios
18-
* Login with Google / Facebook / Github / Twitter OAuth tokens
19-
* Anonymous login
20-
* Login with email + password
21-
* Create new user with email + password
22-
* Send a password reset email
23-
* Link two accounts together
33+
Daily preview builds are also available on [feedz.io](https://feedz.io). Just add the following Package Source to your Visual Studio:
34+
35+
```
36+
https://f.feedz.io/step-up-labs/firebase/nuget/index.json
37+
```
2438

2539
## Usage
2640

41+
In general the terminology and API naming conventions try to follow the official JavaScript implementation, adjusting it to fit the .NET conventions.
42+
E.g. `signInWithCredential` is called `SignInWithCredentialAsync` because it is meant to be `await`ed, but otherwise the terminology should be mostly the same.
43+
44+
45+
### Samples
46+
There are currently 3 sample projects in the [samples folder](/samples/):
47+
48+
* .NET Core Console application (uses only the base library, no UI)
49+
* WPF sample with UI
50+
* UWP sample with UI
51+
52+
Feel free to clone the repo and check them out, just don't forget to add your custom API keys and other setup (typically in `Program.cs` or `App.xaml.cs`).
53+
54+
![](art/SampleWPF.png)
55+
56+
### Setup
57+
58+
For general Firebase setup, refer to the [official documentation](https://firebase.google.com/docs/auth) which discusses the general concepts and individual providers in detail.
59+
You might also want to check out the first two steps in this [web documentation](https://firebase.google.com/docs/web/setup).
60+
Notice that Firebase doesn't officially support Windows as a platform so you will have to register your application as a web app in [Firebase Console](https://console.firebase.google.com/).
61+
62+
### FirebaseAuthentication.net
63+
64+
The base library gives you the same features as the official *Firebase SDK Authentication*, that is without any UI. Your entrypoint is the `FirebaseAuthClient`.
65+
2766
```csharp
28-
var authProvider = new FirebaseAuthProvider(new FirebaseConfig(FirebaseApiKey));
29-
var facebookAccessToken = "<login with facebook and get oauth access token>";
30-
31-
var auth = await authProvider.SignInWithOAuthAsync(FirebaseAuthType.Facebook, facebookAccessToken);
32-
33-
var firebase = new FirebaseClient(
34-
"https://dinosaur-facts.firebaseio.com/",
35-
new FirebaseOptions
36-
{
37-
AuthTokenAsyncFactory = () => Task.FromResult(auth.FirebaseToken)
38-
});
39-
40-
var dinos = await firebase
41-
.Child("dinosaurs")
42-
.OnceAsync<Dinosaur>();
43-
44-
foreach (var dino in dinos)
67+
// main namespaces
68+
using Firebase.Auth;
69+
using Firebase.Auth.Providers;
70+
using Firebase.Auth.Repository;
71+
72+
// Configure...
73+
var config = new FirebaseAuthConfig
4574
{
46-
Console.WriteLine($"{dino.Key} is {dino.Object.Height}m high.");
47-
}
75+
ApiKey = "<API KEY>",
76+
AuthDomain = "<DOMAIN>.firebaseapp.com",
77+
Providers = new FirebaseAuthProvider[]
78+
{
79+
// Add and configure individual providers
80+
new GoogleProvider().AddScopes("email"),
81+
new EmailProvider()
82+
// ...
83+
},
84+
// WPF:
85+
UserRepository = new FileUserRepository("FirebaseSample") // persist data into %AppData%\FirebaseSample
86+
// UWP:
87+
UserRepository = new StorageRepository() // persist data into ApplicationDataContainer
88+
};
89+
90+
// ...and create your FirebaseAuthClient
91+
var client = new FirebaseAuthClient(config);
4892
```
4993

50-
## Facebook setup
94+
Notice the `UserRepository`. This tells `FirebaseAuthClient` where to store the user's credentials.
95+
By default the libraries use in-memory repository; to preserve user's credentials between application runs, use `FileUserRepository` (or your custom implementation of `IUserRepository`).
5196

52-
Under [Facebook developers page for your app](https://developers.facebook.com/) make sure you have a similar setup:
97+
After you have your `client`, you can sign-in or sign-up the user with any of the configured providers.
5398

54-
![Logo](/art/FacebookSetup.png)
99+
```csharp
100+
// anonymous sign in
101+
var user = await client.SignInAnonymouslyAsync();
102+
103+
// sign up or sign in with email and password
104+
var userCredential = await client.CreateUserWithEmailAndPasswordAsync("email", "pwd", "Display Name");
105+
var userCredential = await client.SignInWithEmailAndPasswordAsync("email", "pwd");
106+
107+
// sign in via provider specific AuthCredential
108+
var credential = TwitterProvider.GetCredential("access_token", "oauth_token_secret");
109+
var userCredential = await client.SignInWithCredentialAsync(credential);
110+
111+
// sign in via web browser redirect - navigate to given uri, monitor a redirect to
112+
// your authdomain.firebaseapp.com/__/auth/handler
113+
// and return the whole redirect uri back to the client;
114+
// this method is actually used by FirebaseUI
115+
var userCredential = await client.SignInWithRedirectAsync(provider, async uri =>
116+
{
117+
return await OpenBrowserAndWaitForRedirectToAuthDomain(uri);
118+
});
119+
```
120+
121+
As you can see the sign-in methods give you a `UserCredential` object, which contains an `AuthCredential` and a `User` objects.
122+
`User` holds details about a user as well as some useful methods, e.g. `GetIdTokenAsync()` to get a valid *IdToken* you can use as an access token to other Firebase API (e.g. Realtime Database).
123+
124+
```csharp
125+
// user and auth properties
126+
var user = userCredential.User;
127+
var uid = user.Uid;
128+
var name = user.Info.DisplayName; // more properties are available in user.Info
129+
var refreshToken = user.Credential.RefreshToken; // more properties are available in user.Credential
130+
131+
// user methods
132+
var token = await user.GetIdTokenAsync();
133+
await user.DeleteAsync();
134+
await user.ChangePasswordAsync("new_password");
135+
await user.LinkWithCredentialAsync(authCredential);
136+
```
137+
138+
To sign out a user simply call
139+
```csharp
140+
client.SignOut();
141+
```
142+
143+
### FirebaseUI
55144

145+
The platform specific UI libraries use the `FirebaseAuthClient` under the hood, but need to be initilized via the static `Initialize` method of `FirebaseUI`:
56146

57-
## Google setup
147+
```csharp
148+
// Initialize FirebaseUI during your application startup (e.g. App.xaml.cs)
149+
FirebaseUI.Initialize(new FirebaseUIConfig
150+
{
151+
ApiKey = "<API KEY>",
152+
AuthDomain = "<DOMAIN>.firebaseapp.com",
153+
Providers = new FirebaseAuthProvider[]
154+
{
155+
new GoogleProvider().AddScopes("email"),
156+
new EmailProvider()
157+
// and others
158+
},
159+
PrivacyPolicyUrl = "<PP URL>",
160+
TermsOfServiceUrl = "<TOS URL>",
161+
IsAnonymousAllowed = true,
162+
UserRepository = new FileUserRepository("FirebaseSample") // persist data into %AppData%\FirebaseSample
163+
});
164+
```
165+
166+
Notice the `UserRepository`. This tells FirebaseUI where to store the user's credentials.
167+
By default the libraries use in-memory repository; to preserve user's credentials between application runs, use `FileUserRepository` (or your custom implementation of `IUserRepository`).
168+
169+
FirebaseUI comes with `FirebaseUIControl` you can use in your xaml as follows:
170+
171+
```xml
172+
<!--WPF Sample-->
173+
<Page x:Class="Firebase.Auth.Wpf.Sample.LoginPage"
174+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
175+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
176+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
177+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
178+
xmlns:firebase="clr-namespace:Firebase.Auth.UI;assembly=Firebase.Auth.UI.WPF"
179+
mc:Ignorable="d"
180+
d:DesignHeight="450"
181+
d:DesignWidth="800">
182+
183+
<Grid>
184+
<firebase:FirebaseUIControl>
185+
<firebase:FirebaseUIControl.Header>
186+
<!--Custom content shown above the provider buttons-->
187+
<Image
188+
Height="150"
189+
Source="/Assets/firebase.png"
190+
/>
191+
</firebase:FirebaseUIControl.Header>
192+
</firebase:FirebaseUIControl>
193+
</Grid>
194+
</Page>
195+
```
58196

59-
In the [developer console](https://console.developers.google.com/apis/credentials) make sure you have an OAuth client (set it either as iOS or Android app, that should work).
197+
Toggling the visibility of this UI control is up to you, depending on your business logic.
198+
E.g. you could show it as a popup, or a `Page` inside a `Frame` etc.
199+
You would typically want to toggle the control's visibility in response to the `AuthStateChanged` event:
200+
201+
```csharp
202+
// subscribe to auth state changes
203+
FirebaseUI.Instance.Client.AuthStateChanged += this.AuthStateChanged;
204+
205+
private void AuthStateChanged(object sender, UserEventArgs e)
206+
{
207+
// the callback is not guaranteed to be on UI thread
208+
Application.Current.Dispatcher.Invoke(() =>
209+
{
210+
if (e.User == null)
211+
{
212+
// no user is signed in (first run of the app, user signed out..), show login UI
213+
this.ShowLoginUI();
214+
}
215+
else if (this.loginUIShowing)
216+
{
217+
// user signed in (or was already signed in), hide the login UI
218+
// this event can be raised multiple times (e.g. when access token gets refreshed), you need to be ready for that
219+
this.HideLoginUI();
220+
}
221+
});
222+
}
223+
```

art/FacebookSetup.png

-20.9 KB
Binary file not shown.

art/SampleWPF.png

50.4 KB
Loading

build/build-libs.ps1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
dotnet build --configuration release .\src\Auth\Auth.csproj
2+
dotnet build --configuration release .\src\Auth.UI\Auth.UI.csproj
3+
dotnet build --configuration release .\src\Auth.UI.WPF\Auth.UI.WPF.csproj
4+
msbuild /restore /p:Configuration=Release .\src\Auth.UI.UWP\Auth.UI.UWP.csproj

build/build-samples.ps1

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dotnet build --configuration release .\samples\Console\Auth.Console.Sample.csproj
2+
dotnet build --configuration release .\samples\WPF\Auth.WPF.Sample.csproj
3+
msbuild /restore /p:Configuration=Debug .\samples\UWP\Auth.UWP.Sample.csproj

0 commit comments

Comments
 (0)