Oauth angular and .net core


Problem

We have SPA on Angular and asp.net core. We want to shift the responsobility for users authentification on external oauth server.

Solution

Angular

Install package

npm i angular-oauth2-oidc --save

Importing module in app.module.ts

imports: [
    ...,
    OAuthModule.forRoot()
  ]

Create config in app folder app.auth.config.ts

import { AuthConfig } from 'angular-oauth2-oidc';
 
export const authConfig: AuthConfig = {
 
  // Url of the Identity Provider
  issuer: 'https://...',
 
  // URL of the SPA to redirect the user to after login
  redirectUri: window.location.origin + '/',
 
  // The SPA's id. The SPA is registerd with this id at the auth-server
  clientId: 'clienId',
 
  // set the scope for the permissions the client should request
  // The first three are defined by OIDC. The 4th is a usecase-specific one
  scope: 'openid offline profile.read',
}

In app.component.ts

import { OAuthService } from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc';
import { Component } from '@angular/core';
import { authConfig } from './app.auth.config';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'ClientApp';

  constructor(private oauthService: OAuthService) {
    this.configureWithNewConfigApi();
  }

  private configureWithNewConfigApi() {
    this.oauthService.configure(authConfig);
    this.oauthService.tokenValidationHandler = new JwksValidationHandler();
    this.oauthService.loadDiscoveryDocumentAndLogin();
  }
}

This row says if there is no token goto provider to get it

this.oauthService.loadDiscoveryDocumentAndLogin();


At the writting post time, angular-oauth2-oidc liblary supports only one response type ```id_token token```, so your oauth2 provider should allow such response type for your client.

When you run your app, it goes to issuer ```.well-known/openid-configuration``` and get information about oauth provider 
```json
{
    "issuer": "https://issuer-address/",
    "authorization_endpoint": "https://issuer-address/oauth2/auth",
    "token_endpoint": "https://issuer-address/oauth2/token",
    "jwks_uri": "https://issuer-address/.well-known/jwks.json",
    "subject_types_supported": [
        "public"
    ],
    "response_types_supported": [
        "code",
        "code id_token",
        "id_token",
        "token id_token",
        "token",
        "token id_token code"
    ],
    "claims_supported": [
        "sub"
    ],
    "grant_types_supported": [
        "authorization_code",
        "implicit",
        "client_credentials",
        "refresh_token"
    ],
    "response_modes_supported": [
        "query",
        "fragment"
    ],
    "userinfo_endpoint": "https://issuer-address/userinfo",
    "scopes_supported": [
        "offline",
        "openid"
    ],
    "token_endpoint_auth_methods_supported": [
        "client_secret_post",
        "client_secret_basic",
        "private_key_jwt",
        "none"
    ],
    "userinfo_signing_alg_values_supported": [
        "none",
        "RS256"
    ],
    "id_token_signing_alg_values_supported": [
        "RS256"
    ],
    "request_parameter_supported": true,
    "request_uri_parameter_supported": true,
    "require_request_uri_registration": true,
    "claims_parameter_supported": false
}

Then it redirects to https://issuer-address/oauth2/auth?response_type=id_token token&client_id=clientId&state=F7Jju1p1hL1kGy7J6gTSpFRqiLvqcF6WHZLPT32i&redirect_uri=https://localhost:44366&scope=openid offline profile.read&nonce=F7Jju1p1hL1kGy7J6gTSpFRqiLvqcF6WHZLPT32i

issuer in it’s turn redirect to login page

Don’t forget to add in Configure mehtod

app.UseAuthentication();

This middleware runs on every request, take jwt token from authorization header, validate it and extract user information. Also it goes to oauth server https://issuer-address/.well-known/jwks.json and obtain public keys for validation purpose.

Now we can disallow access to our actions or contoller using [Authorize] data attirubute. For example,

[Authorize]
public class MyController : ControllerBase

And last step, we must send authorization header with each request to actions which require authentication. Following angular-oauth2-oidc library tutorial you can set sendAccessToken to true for automate sending token. However it was not working for me at time writting moment.

So I have to add header explicitly

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    "Authorization": "Bearer " + this.oauthService.getIdToken()
  })
};
//this.baseUrl = baseUrl;
this.http.get<IModel[]>('/api/contorller', httpOptions).subscribe(result => {
  this.generators = result;
}, error => console.error(error));
Buy Me A Coffee

Related Posts

Avoid reflections of mappers and let Mapster generate mappers for you

Mapster generating tool for onion application

Predict Bitcoin price with ML.net

Live time series coin price predictor with machine learning

Throw exceptions from backend to frontend with blazor

One of advantages of using same code language on both frontend and backend

How to avoid violating of SOLID principles while extending service behaviours

Step by step extending service behaviour with decorator pattern respecting SOLID

Blazor render optimization

Best practices

.Net 6 brings application state to blazor webassembly server prerender

It kills strange blinking on screen

Must have libraries for blazor

List of best nuget packages

Blazor virtualize component

Lazy loading of big lists. Rendering optimization.

Blazor grpc - comunication optimization

Smaller and faster requests to your backend from blazor wasm

Free database for your blazor app

Don't pay for the cloud