4
votes

I'm trying to implement Authorization Code Flow for SPA React client with ASP.NET Core and IdentityServer4.

There are two scenarios:

1) User open SPA app, we check if he has an access token and if he hasn't we generate url like

/connect/authorize?
client_id=*client_id*&
redirect_uri=*redirect_uri*&
response_type=code&
response_mode=fragment&
state=*some_state*&
nonce=*some_nonce*&
code_challenge=*code_challenge*&
code_challenge_method=S256&
scope=openid profile email

And so Authorization Code Flow starts. This works pretty clear and after all round trips user comes back to SPA app with code then send request for token (include code and code_verifier) then receive it and with happiness in soul continue using our great application.

2) User opens login page directly and here is where I'm stuck. IdentityServer context knows nothing about this user, code challenges etc. because we didn't make request to /connect/authorize before going to this page as in normal flow. What's next?

I can generate /connect/authorize link directly in login page and do ugly redirect to it and then back to login page (what I don't want to do honestly), but how my SPA app will know what code_verifier I generate here? Of course I can store it in some shared cross-domain cookie, but here should be something better approach I believe.

Another solution I can redirect user from login page to my app, it recognizes that user not authorized and we start scenario #1. Also not my go to approach I think.

What should I do in case user opens my identity server page directly? Is this possible using Authorization Code Flow or should I consider combine some other flows with this one?

I don't want to use Implicit Flow due to new recommendation from OAuth 2.0 specification.

1
+1 VERY nice question! Also I noticed you followed my Materials Modeling Stack Exchange proposal. We are now in the commitment stage and it would be very very helpful if you could click commit! area51.stackexchange.com/proposals/122958/… Only about 2.7% of the people fulfill commitment on new proposals anyway so it doesn't matter if you can't participate much, but it would be helpful to get more users committed before the deadline.user1271772

1 Answers

1
votes

Quite a simple answer to this - in your second scenario - if your user opens IDP login page directly, they didn't want to go to your app. It's the same if you were using Google or Facebook or one of the other known IDP's for your SPA and as a user I just went to their login page instead. They couldn't possibly know if my intention was to ever come to login so that I am later redirected to your SPA.

Now having said all that - what you could do to make this work somewhat seamless - is to redirect to your SPA's protected page after the user logs in through Identity Server 4 (that's simple because you own the login pages and there is no OAuth involved here). Your SPA would then be triggered to initiate the OAuth2 flow and would redirect back to Identity Server 4. The user has already logged in just seconds ago here though, so the login procedure would be skipped and user would either be presented with consent page or if your client is configured to skip consent page - user would be redirected back to your SPA with the usual tokens and such.

So to break it down into the flow:

User Accesses IDS4 Login Page -> User Enters Credentials -> IDS4 Authenticates User and Redirects to your SPA protected page -> Your SPA initiates OAuth2 flow and redirects back to IDS4 -> IDS4 displays consent page -> IDS4 issues auth code back to your SPA.

There is ofcourse extra step here that your SPA will exchange auth code for access token, but I omitted it for clarity purpose as it's not relevant to the question.