I have a question about implementing OpenID Connect I was hoping I could get some help on. I understand the different flows and get that the authorization code flow is good because it allow client credentials and server-to-server communication is more secure than communication through the user agent. But even so using the intermediary code seems unnecessary if the client and OP were to use authenticated encryption on their correspondence through the user agent. Groundhog Day attacks could either be restricted through the use of a very short expiration time specified within the message or eliminated with a preliminary request to the OP for a nonce. Assuming a strong enough encryption, i.e. AES-256, I would think that even refresh tokens could be sent through the user agent with negligible decrease in security. Are there any other considerations or reasons why this could/should not be done that I may have overlooked?
Even though the connection between user agent and servers are secure, the user agent may not be fully protected. Since authorization code flow ensures the user agent is not privy to the tokens, security is improved by reducing exposure of tokens to between servers only.
There is some additional level of security. When a request is made to the Token endpoint to exchange the code received from the Authorize endpoint it allows the client application to authenticate itself to the authorization server. When you make a request to the Token endpoint you send more data about the client. For confidential clients (applications that are capable of securely storing a client secret) the token endpoint requires the client to authenticate itself by means of a client id and client secret. See this section of the OAuth 2.0 spec and this section of the OpenID Connect spec. To summarize, the client application can send the client id and client secret in two ways. One way is by using the pair as a username/password combination via HTTP Basic authentication and the other sending the credentials in the POST body of the Token endpoint request. I must add that only confidential client types are required to send the client id/client secret pair. Public client types typically don't call the Token endpoint*** For example, implicit flow only uses the Authorize endpoint. One of the reasons implicit flow is considered less secure is because the client application never authenticates itself with the authorization server. Implicit flow only sends a client id and it's to the Authorize endpoint which does not support a client secret or any way for the client to authenticate itself. Note that sending only the client id is not authenticating the client. It's only identifying it.
The bottom line: when you use authorization code flow you are authenticating your client and thus adding another layer of security.
In implicit grant, which seems to be under consideration, the tokens are returned from the authorization endpoint in the redirection URL and will be logged in the browser history.
For confidential clients tokens may travel over secure back-channel and don't have to be exposed to the user agent in authorization code flow.