.NET 6.0 library (maintained since 2019) that allows easy integration of external OAuth providers (Google, Facebook, etc.) into your SPA. It is most useful together with IdentityServer.
With IdentityOAuthSpaExtensions you can integrate Login with Facebook or Login with Google buttons right inside your SPA (React/Angular/whatever) without the need to redirect to server-side UI for authentication.
Here's the demo if you care. The shown page uses vanilla JS, and has several buttons to log in via different providers.
- You could add Social Log In buttons inside your SPA (so you don't need to show default Identity UI to your users)
- On SPA side you could receive AuthCode from OAuth provider (Authorization Code Flow)
- On backend you could verify AuthCode (passed from your SPA) and get user information from oAuth provider
- If you're using IdentityServer, you could plug-in an extension grant that will allow you to issue your own JWT tokens in exchange for AuthCode (and optionally create new users).
The project goal is to allow integration of external OAuth providers (e.g. Google, Facebook, etc.) into your SinglePageApplications applications (React, Angular, plain-old-js, whatever), with minimum amount of needed code, and without the need to show Identity UI to the user.
This is a backend library, that integrates with Asp.Net Core 5.0+.
The library is kept minimal, as we reuse all official and non-official authentication providers (i.e. library doesn't need to be updated when those external providers change).
Library is significantly reworked in v1.0, so there's no provider-specific code at all.
-
Install nuget to add the library to your project.
dotnet add package IdentityOAuthSpaExtensions
-
From
ConfigureServices
callservices.ConfigureExternalAuth()
. -
From
Configure
callapp.UseExternalAuth()
BEFOREUseAuthentication()
. -
If you are using IdentityServer, add the grant validator:
services.AddIdentityServer().AddExtensionGrantValidator<ExternalAuthenticationGrantValidator<IdentityUser, string>>()
.Also include 'external' grant type to existing grant types of your Client (SPA)
-
That's it. Just
.AddAuthentication().AddGoogle()
or.AddFacebook()
as usual. Follow instructions on how to set up applications on OAuth provider side.
You could also take a look at IdentityOAuthSpaExtensions.Example for example usage (keep in mind, that there are hardcoded ClientId/ClientSecret for FB and Google within Example app. They are for demo purposes and everyone can use them, so beware).
- Copy the following typescript (or compiled JS) file into your sourcecode (adjust the
backendUri
variable on top if your SPA is on different host than backend). - Place some SocialLogin buttons in your SPA and execute
getOAuthCode('Google')
from onClick handler. - Request access token from your Identity Server, passing received oAuthCode to it. In total you should have something like this:
// call this function from SocialLogin buttons onClick async function signInVia(provider) { const data = await getOAuthCode(provider); await getAccessToken(data.provider, data.code); } async function getAccessToken(provider, code) { const response = await fetch('/connect/token', { method: 'POST', // you will need to adjust SCOPE here body: grant_type=external&scope=local&provider=${provider}&code=${code}`, headers: { // you definitely need to use clien/secret of YOUR APP here 'Authorization': 'Basic Y2xpZW50OnNlY3JldA==', //base64 encoded 'client:secret' 'Content-Type': 'application/x-www-form-urlencoded', } }); const jsonData = await response.json(); _accessToken = jsonData.access_token; alert('access_token: '+ _accessToken); // make some requests to your API using this token! }
Typical scenario is that you use oAuth for authentication only, and then create the user in your local DB (via e.g. IdentityServer) and issue your own JWT with custom claims for later authorization.
This library perfectly supports this scenario in combination with IdentityServer using extension grants (https://docs.identityserver.io/en/latest/topics/grant_types.html#extension-grants).
To integrate with IdentityServer all you need to do is call
services.AddIdentityServer().AddExtensionGrantValidator<ExternalAuthenticationGrantValidator<IdentityUser, string>>()
.
That will register an extension grant named external
and you could authenticate from JS as described above
You could inherit from ExternalAuthenticationGrantValidator<IdentityUser, string>
and provide your custom logic for any of the following methods:
CreateNewUser
- fill-in the fields of new User based on your business requirements and/or information received from oAuth providerCreateResultForLocallyNotFoundUser
- here you could write your own business logic, regarding what to do when the user is logging in for the first time. You could write custom logic for user creation, or deny some users (based on email/id) from logging in.GetUserName
- most useful if you don't overrideCreateNewUser
. You could provide Username for newly created users based on oAuth provider info
We use standard Asp.Net Identity mechanism to store external logins (namely, AspNetUserLogins
table). To find a user by external OAuth id you need to use _userManager.FindByLoginAsync(providerName, externalUserId)