7
votes

I want to build an (Angular) SPA with a (Asp.Net Core) back-end and I want to use security best practices. My plan is this:

  1. The SPA displays a Login button
  2. Clicking the Login button initiates an authorization code openid-connect flow with some identity provider (Google, Microsoft, etc.)
  3. The user authenticates with the identity provider and then is redirected back to the SPA with the authorization code
  4. The SPA then makes a login request to the back-end and passes the authorization code
  5. The back-end makes a request to the identity provider, exchanging the code for an id_token, and creates some kind of session ticket for the user

Now this is where I get bogged down by my lack of proper understanding

Issue 1 - Best Practice

Is the above procedure even considered best practice? Or am I doing it wrong?

Issue 2 - Authentication Ticket

My back-end is API only, it doesn't render HTML pages for the user, only provides Json responses. What kind of authentication ticket should I create? Should it be a JWT or a Cookie? I assume it can't be a cookie since API cannot return a cookie that the browser will store properly. So it must be some kind of token, preferably a JWT. How should the SPA store it, local / session storage?

Issue 3 - Expiration and Refresh

Assuming the back-end returns a JWT to the SPA, what should this JWT contain? What should be its expiration time? How should I handle automatic refreshing?

Issue 4 - Required Packages & Libraries

Also, specific to programming (since this is a programming question after all), what are the required libraries to use for all of this. The question is both for the SPA and for the back-end. I assume I need some kind of openid-connect client for the SPA, and I need some library on the back-end which can complete the authorization code flow (exchanging the code for the id_token) is this done by IdentityServer4? Or is there some other library.

UPDATE

I've prepared a solution which strives to showcase the proper way to do everything. It is a work in progress, messy and unclean, but it is minimal, and it works and it strives to follow best practices.

https://github.com/paviad/dotnet-angular-fullstack

1
Can you share your solution? I'm in the same situation except using Vue for SPA. ThanksStackUndefined
@sanmcp check out my latest update to the question. See repo at github.com/paviad/dotnet-angular-fullstackAviad P.

1 Answers

2
votes

OpenID Connect is a standard (on top of the OAuth 2.0) and it has many flows (you mentioned one Authorization Code flow, which is not the best for SPA.

There was recommended Implicit flow for SPA apps, where SPA receives tokens directly from IdP. Implicit flow is deprecated now and Authorization Code with PKCE Flow is the best option for SPA at the moment. This random blog post will give you more details about these flows.

SPA may receives also refresh token, which can be used to get new access token, but it depends on used IdP.

Backend just need library to verify token (from request Authorization header), eventually it needs to verify some claims (e.g. role) for optional authorizations. It doesn't need to handle any OIDC flow, because it communicates via response code usually (200, 401, 403, 500, ...) back to SPA and SPA handles errors.

IMHO just select suitable library (prefer OIDC certified) for your SPA (my favorite for Angular) and it will provide many useful SPA features out of the box (correct flow, token refresh, token storage, http Interceptor for backend calls, ...). I would avoid any IdP provided libraries - it can be quick win for implementation, but it can be IdP vendor lock-in if they provide some functionality outside of OIDC standard.