ddelella
ddelella

Reputation: 67

IdentityServer3 + Angular4 + WebApi Causing 401 Unauthorized

I am having trouble with implementing IdentityServer3 token authorization in my WebApi. My solution has a .NET Core Angular 4 client side project and a separate .NET Framework 4.5.2 WebApi project. The WebApi has been tested and is working before adding the token authorization. The IdentityServer3 login and authentication is working as well. I am using the angular-auth-oidc-client node module. I have verified that the Request Header is getting the designated properties set for Content-Type, Accept and Authorization. Here is the code for some of the key files.

user-list.component.ts

import { Component, OnInit } from '@angular/core';
import { Http, Headers, Response } from '@angular/http';
import { Subject } from 'rxjs/Rx';
import { OidcSecurityService } from 'angular-auth-oidc-client';

import 'rxjs/add/operator/map';

class User {
    userId: number;
    firstName: string;
    middleName: string;
    lastName: string;
    email: string;
}

@Component({
    selector: 'user-list',
    templateUrl: './user-list.html',
    styleUrls: ['./user-list.css']
})
export class UserListComponent implements OnInit {
    dtOptions: DataTables.Settings = {};
    users: User[] = [];

    dtTrigger: Subject<User> = new Subject();

    constructor(private http: Http, private securityService: OidcSecurityService) { }

    ngOnInit(): void {
        this.dtOptions = {
            searching: true,
            pagingType: 'full_numbers',
            pageLength: 5,
            info: false,
            lengthChange: false
        };

        let headers = new Headers();
        headers.append('Content-Type', 'application/json');
        headers.append('Accept', 'application/json');
        headers.append('Authorization', 'Bearer ' + this.securityService.getToken());

        //this.dtOptions = this.http.get('api/settings/datatables')
        //    .toPromise()
        //    .then(response => response.json());

        this.http.get('/api/home', { headers })
            .map((response: Response) => response.json())
            .subscribe(users => {
                this.users = users;
                this.dtTrigger.next();
            });
    }
}

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app.routes';
import { DataTablesModule } from 'angular-datatables';

import { AppComponent } from './app.component';
import { UserListComponent } from './user-list/user-list.component';
import { PostalCodeComponent } from './postal-code/postal-code.component';

import { AuthModule, OidcSecurityService, OpenIDImplicitFlowConfiguration } from 'angular-auth-oidc-client';

@NgModule({
    declarations: [
        AppComponent,
        UserListComponent,
        PostalCodeComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        HttpModule,
        DataTablesModule,
        AuthModule.forRoot()
    ],
    providers: [OidcSecurityService],
    bootstrap: [AppComponent]
})
export class AppModule {
    constructor(public oidcSecurityService: OidcSecurityService) {
        let settings = new OpenIDImplicitFlowConfiguration();
        settings.stsServer = 'https://identitydev.company.com/oidc/core';
        settings.redirect_url = 'http://localhost:4200';
        settings.client_id = '802523112846585';
        settings.response_type = 'id_token token';
        settings.scope = 'openid app_profile app_client_api';
        settings.post_logout_redirect_uri = 'http://localhost:4200';
        settings.startup_route = '/';
        //settings.forbidden_route = '/Forbidden';
        //settings.unauthorized_route = '/Unauthorized';
        settings.log_console_warning_active = true;
        settings.log_console_debug_active = true;
        //settings.max_id_token_iat_offset_allowed_in_seconds = 10;
        //settings.override_well_known_configuration = true;
        //settings.override_well_known_configuration_url = 'https://localhost:44386/wellknownconfiguration.json';

        // this.oidcSecurityService.setStorage(localStorage);
        this.oidcSecurityService.setupModule(settings);
    }
}

Startup.cs

using Microsoft.Owin;
using Owin;
using System.Web.Http;
using IdentityServer3.AccessTokenValidation;
using System.Net.Http.Headers;
using Microsoft.Owin.Security.OAuth;

[assembly: OwinStartup(typeof(App.API.Test.Startup))]
namespace App.API.Test
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://identitydev.company.com/oidc/core",
                //RequiredScopes = new[] { "app_client_api" },
                ValidationMode = ValidationMode.ValidationEndpoint
            });

            // configure web api
            var config = new HttpConfiguration();
            config.MapHttpAttributeRoutes();
            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
            app.UseWebApi(config);
        }
    }
}

HomeController.cs

using System.Collections.Generic;
using System.Security.Claims;
using System.Web.Http;
using TRAX.Models;

namespace App.API.Test.Controllers
{
    [Authorize]
    [Route("api/home")]
    public class HomeController : ApiController
    {
        [HttpGet]
        public IEnumerable<User> Get()
        {
            UserList list = new UserList();
            return list.GetAll;
        }

        //// GET api/home/{firstname}
        //[HttpGet("{FirstName}")]
        //public List<User> GetByFirstName(string FirstName)
        //{
        //    UserList list = new UserList();
        //    return list.GetUserByFirstName(FirstName);
        //}
    }
}

** Note: There is a model that goes with this controller to return the data but you can trust that it is returning the correct list.

Upvotes: 0

Views: 474

Answers (1)

ddelella
ddelella

Reputation: 67

Apparently the solution was to remove the Global.ascx file that Microsoft created in the template project. I then updated the Startup.cs file as such.

using Microsoft.Owin;
using Owin;
using System.Web.Http;
using IdentityServer3.AccessTokenValidation;

[assembly: OwinStartup(typeof(App.API.Test.Startup))]
namespace App.API.Test
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
            {
                Authority = "https://identitydev.company.com/oidc/core",
                RequiredScopes = new[] { "app_client_api" },
                ValidationMode = ValidationMode.ValidationEndpoint
            });

            WebApiConfig.Register(config);
            app.UseWebApi(config);
        }
    }
}

I also did not need to include the Content-Type or Accept header overrides from the client side API call. I return JSON by default from the WebApi.

Upvotes: 1

Related Questions