https://github.com/barzin144/microidp
Micro IDP Service
https://github.com/barzin144/microidp
dotnet dotnet8 google-sign-in jwt jwt-auth jwt-authentication jwt-bearer-tokens jwt-token mongodb webapi-core
Last synced: 4 months ago
JSON representation
Micro IDP Service
- Host: GitHub
- URL: https://github.com/barzin144/microidp
- Owner: barzin144
- License: mit
- Created: 2020-09-03T22:54:54.000Z (over 5 years ago)
- Default Branch: master
- Last Pushed: 2025-09-06T13:43:44.000Z (4 months ago)
- Last Synced: 2025-09-06T15:26:59.001Z (4 months ago)
- Topics: dotnet, dotnet8, google-sign-in, jwt, jwt-auth, jwt-authentication, jwt-bearer-tokens, jwt-token, mongodb, webapi-core
- Language: C#
- Homepage:
- Size: 139 KB
- Stars: 9
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Micro IDP Service
## Features
- Sign up/in with Email
- Sign up/in with Google
## Run in Docker
### Generate certificate to host application with Docker over HTTPS
#### Windows
```shell
dotnet dev-certs https -ep %USERPROFILE%\.aspnet\https\aspnetapp.pfx -p
dotnet dev-certs https --trust
```
In the preceding commands, replace `` with a password.
#### Linux
```shell
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout aspnetcore.key -out aspnetcore.crt -subj "/CN=localhost"
openssl pkcs12 -export -out aspnetcore.pfx -inkey aspnetcore.key -in aspnetcore.crt
```
Replace **_ASPNETCORE_Kestrel\_\_Certificates\_\_Default\_\_Password_** with the certificate password in `.env`.
Replace the volume mount source with the generated certificate path in `docker-compose.yml`:
```yml
volumes:
- type: bind
source: ./aspnetcore.pfx
target: /https/aspnetcore.pfx
```
To share data protection keys for encrypting and decrypting cookies, create an empty folder and bind it into the Docker container:
```yml
volumes:
- type: bind
source: ./DataProtectionKeys
target: /app/DataProtectionKeys
```
### Generate Private and Public Key
#### C# Interactive
```csharp
using System.Security.Cryptography;
using (var rsa = RSA.Create(2048))
{
// Export the private key
var privateKey = rsa.ExportRSAPrivateKey();
var privateKeyBase64 = Convert.ToBase64String(privateKey);
Console.WriteLine("Private Key:");
Console.WriteLine(privateKeyBase64);
// Export the public key
var publicKey = rsa.ExportRSAPublicKey();
var publicKeyBase64 = Convert.ToBase64String(publicKey);
Console.WriteLine("\nPublic Key:");
Console.WriteLine(publicKeyBase64);
}
```
#### Bash
```shell
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
cat private_key.pem | base64
openssl rsa -pubout -in private_key.pem -out public_key.pem
cat public_key.pem | base64
```
Replace the `PRIVATE_KEY` placeholder in `.env` with the generated private key.
### Sign in with Google Configuration
1. Create an OAuth 2.0 client in [Google Cloud Console](https://console.cloud.google.com).
2. Replace **_OAuth\_\_GoogleClientId_** placeholder in `.env`.
3. Replace **_OAuth\_\_GoogleClientSecret_** placeholder in `.env`.
4. Replace **_OAuth\_\_GoogleCallBackURL_** placeholder in `.env` with your client app's Google callback page (this page should call `https://IDP_SERVER_URL/api/auth/google-callback` to get JWT).
### Run IDP
```shell
docker compose up --wait
```
## Client App
### Add Jwt Section to Your `appsettings.json`
```json
"Jwt": {
"PublicKey": "PUBLIC_KEY",
"Issuer": "https://localhost:8001",
"Audience": "http://localhost:5010",
"DataProtectionApplicationName": "microidp",
"DataProtectionKeysPath": "./DataProtectionKeys",
"CookieName": "SAME AS IDP .env Jwt__CookieName",
"DataProtectionPurpose": "SAME AS IDP .env Jwt__DataProtectionPurpose"
}
```
Replace the `PUBLIC_KEY` placeholder with the generated public key.
### Install JwtBearer Package
```shell
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
```
### Add Authentication Middleware
```csharp
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(configuration["Jwt:DataProtectionKeysPath"] ?? ""))
.SetApplicationName(configuration["Jwt:DataProtectionApplicationName"] ?? "");
var rsa = RSA.Create();
rsa.ImportRSAPublicKey(Convert.FromBase64String(configuration["Jwt:PublicKey"] ?? ""), out _);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = configuration["Jwt:Issuer"],
ValidAudience = configuration["Jwt:Audience"],
IssuerSigningKey = new RsaSecurityKey(rsa)
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
if (context.Request.Cookies.TryGetValue(configuration["Jwt:CookieName"], out var encryptedToken))
{
var dataProtector = context.HttpContext.RequestServices
.GetRequiredService()
.CreateProtector(configuration["Jwt:DataProtectionPurpose"]);
try
{
var authCookie = JsonSerializer.Deserialize(dataProtector.Unprotect(encryptedToken));
context.Token = authCookie.AccessToken;
}
catch
{
context.Fail("Invalid or tampered token");
}
}
return Task.CompletedTask;
}
};
});
```