External API's Calling My API Secured with Azure Active Directory - oauth

If I have an API secured with Azure Active Directory, what is the flow when an external API wants to talk to my internal API?
Is this just an API to API call as normal or is this a special circumstance and needs handling a different way?

Is this just an API to API call as normal or is this a special circumstance and needs handling a different way?
The special circumstance may depend on the confidentiality of the resources served by these api(s) and the level of security your application needs. In the end it is an api to api call only.
There are two approaches you can use if Azure Active Directory (AAD) is your Identity Provider for the entire application.
Application Identity with OAuth 2.0 client credentials grant provided by AAD. The calling API makes a request to AAD token endpoint with its client id, client secret (credential) and the application id (the unique id for the callee API) to receive an access token as response. This token is used as Bearer token to call the downstream API. In this approach client id, client secret, application id that are exchanged for an access token, are static values. Some one who has access to these values may find a way to compromise application security (highly unlikely).
The second approach is Delegated User Identity with OAuth 2.0. A request is made to AAD token endpoint with client id, client secret, the access token received as part of calling the tier1 API and a special on_behalf_of parameter to receive an access token, refresh token as response. We preferred this approach as it uses a dynamic value (access token from tier1 api) and also provides a refresh token.
You can read more about these approaches here
If you do not want to use AAD, you can use asp.net built in OwinAuthenticationMiddleware to generate and validate your own access tokens. As said earlier it all depends on your application requirements and implementation details, but in the end it is an API to API call.
Hopefully this is helpful, please let me know if you have any questions.
Thank you,
Soma.

oAuth is done for loggin user to a webservice (see also reference here).
Use OAuth to give your users access to their data while protecting their account credentials.
As another webservice wants to consume one of your service best way to do so is to have another authentication method in order to authorize
Other API, I assume you are talking of machines and not users (alias humans).
So best way is to provide another auth mechanism in order to authorize machines to connect to your API in a safe way.
A simple way to do a machine connection is using a private PKI with public/private key.
A good reference for PKI : http://docs.oracle.com/javase/6/docs/technotes/guides/security/certpath/CertPathProgGuide.html

Related

How to authenticate mobile app to web service using Azure AD?

Currently I have this setup:
At login, and in every subsequent request after login, a mobile application that I have built uses Basic Authentication to authenticate the user with a web service that serves the app with information it requests.
On every request the Authorization header is inspected, the password and username are extracted from the header, the password is hashed using a proprietary DLL (so the web service doesn't actually contain the hashing algorithm) and compared to the hashed password associated with the username that is stored in the database.
I have now been asked to include Azure AD SSO in the login options.
After reading much about the topic, this looks seems to me like the setup:
I'm curious about a few things:
Is this setup correct, more or less?
Does the app send the Identity Token to the web service? If so, how does the webservice validate that token?
Is it correct that the webservice can match the Azure Identity to the DB user using one of the claims in the Security Token?
Where do Access Token fit in this picture?
Thanks for the help!
(Side Note: I know that Basic Authentication is not the preferred way to go in the first scenario. This was a temporary decision till we developed the token handling code, it only works using HTTPS and this is an internal application - you wouldn't be able to activate the app unless you have a code we give you)
I have little experience in azure ad but I think we could talk about your case.
First, whatever id token and access token are both jwt token, so to your web service application, you need to use jwt decode library to decrypt the token and get claims it contains. Here we need to know the difference between id token and access token, and I think you'll know that for your web service application, if it's more likely to play the role of an api application, you need to use access token because this token also contains user information. Then you need to add code in your program to decode the token and check if it's a 'valid' token for the request.(Because you've used azure ad to achieve the login part, you don't need to use your custom login part.)
Next, the signing in feature provided by azure ad requires to use account and password in the tenant which azure ad belongs to, the user accounts may look like xx#xx.onmicrosoft.com, it doesn't required to keep sycn with the accounts in your database, so it's difficult and needless for you to compare the user name obtained from the decoded token with those in your database. Because when your web service received the token(id or access token), that means someone has passed the authentication from azure ad. The token contains user information including role, expired time etc. You need to check if the token has expired and if has the correct scope. (Let's see a common situation, microsoft provides many graph apis to call, when accessing these api, we need to provide access token in request head with matching scope, e.g. https://graph.microsoft.com/v1.0/me
requires a delegated api permission of User.Read)
To sum up here, if your web service just required the users in your database to sign in then can be access, id token and access token are both suitable for you because they both contains user name like 'xx#xx.onmicrosoft.com', what you need to do is decode the token and check if the token has expired and whether this user exists in your database(you may set up a mapping between them).

Can Oauth be used securely from the client side for a back-end service?

I have a web app (C# / Javascript) where I want to call a back-end service that I own. I want to secure that service so only my app(s) can call it. Seems like if I use Oauth on the client side, the secret is exposed? All the docs I read about Oauth give solutions when the user of the app owns the resource, not when the app itself owns it. I was looking at how google apis work, and the JavaScript libraries seem to expose the key on the client side, no?
Yes you can accomplish this with OAuth, but how you go about it depends on the details of how the data accessed via your back-end service is organized. If the data is actually user-specific, then your user really is the resource owner. In this case you would use the typical authorization code grant. With this grant type you register a client with the OAuth auth server and receive a client_id and client_secret. The client_id is, indeed, exposed in the browser, but the client_secret sits in your web app server and is never exposed. It is only sent on back-channel (non-browser) requests to your auth server. The main thing here is that only your own client web app would be registered and receive the client_id/client_secret. You simply need to not provide any public registration endpoints so no other clients can register. With this grant type, in order for your web app to gain authorization to access the user's data on the back-end service, the user would need to approve the authorization in the browser as part of the process.
On the other hand if the data you're accessing on your back-end service is not user-specific, then you can use the OAuth Client Credentials grant. With this grant type you register the client as before and receive a client_id and client_secret. The secret is stored securely on your web app server and only passed in back-channel requests. You would avoid allowing any other clients to register. Your web app can then gain authorization to your back-end service without even needing any user authorization in the browser.
I'm afraid there is no way to restrict your API to be called just by the code of your applications. Browser applications with public codes cannot hold any secret (such as certificate), that would identify them, because anyone can extract it from the code. Desktop and mobile applications compiled to bytecode are not so easy to read, but with some effort, attacker could find the secret data. That's also the reason why these applications (so called public clients) don't hold client_secret if they act as OAuth2 clients. They use a one-time secret instead - PKCE.
What you can do, is to check the audience (what client ID the token was issued for) of an access token sent from a frontend application to your backend. You can get this info either from the token introspection endpoint (aud attribute) or from JWT attributes if the token is of JWT type.

How to obtain OAuth access tokens in a public javascript application with no logged in user?

I'm developing a JavaScript application that needs to interact with an API that's protected with OAuth. However, there users of this JavaScript application don't have accounts anywhere - they are anonymous visitors to a public website. The data in the API results in public, but it's still being protected by OAuth2.
I examined all the available grant types at my disposal and none of them really make sense in this scenario.
The "implict" grant type seems appropriate for use in JavaScript applications, but it also assumes that the visitor to the site is a resource owner and the process to obtain the token requires them to "approve" access to the resources. That wouldn't work, because there's no user account that they'd be logging into on the identity server.
I believe my options are:
Output the client ID and secret directly into the page, and have
JavaScript use the client_credentials grant type to obtain a token.
Obviously anyone could scrape this and use it outside the
application... but it's public data anyway
Have the web server obtain a new token for each visitor to the page
via the client_credentials grant type. Once it obtains the token, it
dumps it into the page body so that the JavaScript app can use it
when making API requests. This hides the client ID and secret from
JavaScript, but it forces the web server to serve as a seemingly
pointless middleware for accessing the API. Someone could also just
scrape the token from the page... but it's public data anyway.
Remove OAuth protection from the endpoints entirely (not sure if
this is even feasible with WSO2 API Manager). It's public data.
Am I overlooking something?
Remove OAuth protection from the endpoints entirely (not sure if this is even feasible with WSO2 API Manager). It's public data.
Yes, for public access this is completely feasible option. You can configure no authorization for resources of API and no OAuth token will be required. As a downside - you won't get any statistics of it.
Output the client ID and secret directly into the page.. but it's public data anyway
If the credentials are not used used for any other application (resp. non-public access), it should be ok. What you can even do is create a permanent access token (with validity -1). Indeed using this option you may consider the client credentials public.
Have the web server obtain a new token for each visitor to the page via the client_credentials grant type.
Having the same application the WSO2 APIM will return the same token for the same application while the token is not expired. Though technically this is the right approach when having OAuth authorized data with client credentials.

How to implement OpenID Connect authentication with 3rd party IDPs in a microservices architecture

For the past 10+ days I've read an watched ALL the content I could find on understanding OAuth2 and OpenID Connect, only to find that many people disagree on the implementation, which really confuses me.
To my understanding, all the articles and examples I found assume you want access to eg. google calendar, profile info or emails if you eg. login with google, but I do NOT need to access other than my own API's - I only want to use Google, Facebook etc for logging in, and getting an id which I can link to my user in my own database - nothing more than that.
I'll try illustrate my use case and use that as an example.
A note on the diagram: the Authentication service could probably be built into the API Gateway - not that i matters for this example, since this is not about "where to do it", but "how to do it the best way" possible, for an architecture such as mine, where it's used for my own API's / Microservices, and not accessing Google, Facebook etc. external API's
If you can understand what I'm trying to illustrate with this diagram above, please tell me if I've misunderstood this.
The most basic requirements for this architecture you see here are:
Users can login with Google, Facebook, etc.
The same login will be used for all micro-services
OpenId user will have a linked account in the database
User access is defined in my own db, based on groups, roles and permissions
I do not intend to use external API's after the user is authenticated and logged in. No need for ever accessing a users calendar, email etc. so I really just need the authentication part and nothing else (proof of successful login). All user access is defined in my own database.
So a few fundamental questions comes to mind.
First of all, is OpenID Connect even the right tool for the job for authentication only (I'll have no use for authorization, since I will not need read/write access to google / facebook API's other than getting the ID from authenticating)?
People generally do not agree on whether to use the ID or Access token for accessing your own API's. As far as I understand the ID token is for the client (user-agent) only, and the access token is for eg. accessing google calendar, emails etc.... External API's of the OpenID Provider... but since I'll only be accessing my own API's, do I event need the access token or the ID token - what is the correct way to protect your own API's?
If the ID token is really just for the client, so it can show eg. currently logged in user, without going to the DB, I have 0 use for it, since I'll probably query the user from from the db and store it in redux for my react frontend app.
Dilemma: To store user details, groups, roles and permission inside JWT or not for API authorization?
By only storing the user identifier in the token, it means that I always allow authenticated users that has a valid token, to call endpoints BEFORE authorization and first then determine access based on the db query result and the permissions in my own database.
By storing more data about the user inside the JWT, it means that in some cases, I'd be able to do the authorization / access (group, role, permission) check before hitting the API - only possible with user info, groups, roles and permission stored inside a JWT issued upon login. In some cases it would not be possible due to eg. the CMS content access permissions being on a per-node level. But still it would mean a little better performance.
As you can see on the diagram I'm sending all API requests through the gateway, which will (in itself or with an authentication service) translate the opaque access token into some JWT with an identifier, so I can identify the user in the graph database - and then verify if the user has the required groups, roles and permissions - not from an external API, but from my own database like you see on the diagram.
This seems like a lot of work on every request, even if the services can share the JWT in case multiple services should need to cross call each other.
The advantage of always looking up the user, and his permissions in the db, is naturally that the moment the user access levels change, he is denied/granted access immediately and it will always be in sync. If I store the user details, groups, roles and permission inside a JWT and persist that in the client localstorage, I guess it could pose a security issue right, and it would be pretty hard to update the user info, groups, roles and permissions inside that JWT?
One big advantage of storing user access levels and info inside the JWT is of course that in many cases I'd be able to block the user from calling certain API's, instead of having to determine access after a db lookup.
So the whole token translation thing means increased security at the cost of performance, but is is generally recommended and worth it? Or is it safe enough to store user info and groups, roles, permissions inside the JWT?
If yes, do I store all that information from my own DB in the ID Token, Access token or a 3rd token - what token is sent to the API and determines if the user should be granted access to a given resource based on his permissions in the db? Do I really need an access token if I don't need to interact with the ID providers API? Or do I store and append all my groups, roles, permissions inside the ID token (that doesn't seem clean to me) issued by OpenID connect, and call the API and authorize my own API endpoints using that, even if some say you should never use the ID token to access an API? Or do I create a new JWT to store all the info fetched from my database, which is to be used for deciding if the user can access a given resource / API endpoint?
Please do not just link to general specs or general info, since I've already read it all - I just failed to understand how to apply all that info to my actual use case (the diagram above). Try to please be as concrete as possible.
Made another attempt to try and simply the flow:
The following answer does only apply for a OpenID Connect authentication flow with a 3rd party IDP (like Google). It does not apply for an architecture where you host your own IDP.
(There are some API gateways (e.g Tyk or Kong) which support OpenID Connect out of the box.)
You can use JWTs (ID token) to secure your APIs. However, this has one disadvantage. JWTs cannot be revoked easily.
I would not recommend this. Instead you should implement an OAuth2 authorization server which issues access tokens for your API. (In this case, you have two OAuth2 flows. One for authentication and one for authorization. The ID and access token from the IDP are used only for authentication.)
The following picture shows a setup where the API gateway and authentication/authorization server are two separate services. (As mentioned above, the authentication/authorization can also be done by the API gateway.)
The authentication flow (Authorization Code Grant) calls are marked blue. The authorization flow (Implicit Grant) calls are marked green.
1: Your web app is loaded from the app server.
2a: The user clicks on your login button, your web app builds the authorization URL and opens it. (See: Authorization Request)
2b: Because the user hasn't authenticated and has no valid session with your authorization server, the URL he wanted to access is stored and your authorization server responds with a redirect to its login page.
3: The login page is loaded from your authorization server.
4a: The user clicks on "Login with ...".
4b: Your authorization server builds the IDP authorization URL and responds with a redirect to it. (See: Authentication Request)
5a: The IDP authorization URL is opend.
5b: Because the user hasn't authenticated and has no valid session with the IDP, the URL he wanted to access is stored and the IDP responds with a redirect to its login page.
6: The login page is loaded from the IDP.
7a: The user fills in his credentials and clicks on the login button.
7b: The IDP checks the credentials, creates a new session and responds with a redirect to the stored URL.
8a: The IDP authorization URL is opend again.
(The approval steps are ignored here for simplicity.)
8b: The IDP creates an authorization and responds with a redirect to the callback URL of your authorization server. (See: Authentication Response)
9a: The callback URL is opened.
9b: Your authorization server extracts the authorization code from the callback URL.
10a: Your authorization server calls the IDP's token endpoint, gets an ID and access token and validates the data in the ID token. (See: Token Request)
(10b: Your authorization server calls the IDP's user info endpoint if some needed claims aren't available in the ID token.)
11a/b: Your authorization server queries/creates the user in your service/DB, creates a new session and responds with a redirect to the stored URL.
12a: The authorization URL is opend again.
(The approval steps are ignored here for simplicity.)
12b/+13a/b: Your authorization server creates/gets the authorization (creates access token) and responds with a redirect to the callback URL of your web app. (See: Access Token Response)
14a: The callback URL is opened.
14b: Your web app extracts the access token from the callback URL.
15: Your web app makes an API call.
16/17/18: The API gateway checks the access token, exchanges the access token with an JWT (which contains user infos, ...) and forwards the call.
A setup where the authorization server calls the API gateway is also possible. In this case, after the authorization is done, the authorization server passes the access token and JWT to the API gateway. Here, however, everytime the user infos change the authorization server has to "inform" the API gateway.
This is a very long question. But I believe most can be summarised by answering below,
To my understanding, all the articles and examples I found assume you want access to eg. google calendar, profile info or emails if you eg. login with google,
You do not necessarily use Access token (ID token in some occasions) to access the services offered by token issuer.You can consume tokens by your own APIs. What these Identity Providers (synonym to Authorization server, or IDP in shorthand) is to hold identities of end users. For example, typical internet have a Facebook account. With OAuth and OpenID Connect, the same user get the ability to consume your API or any OAuth/OIDC accepted service. This reduce user profile creation for end users.
In corporate domain, OAuth and OIDC serves the same purpose. Having a single Azure AD account lets you to consume MS Word as well as Azure AD's OIDC will issue tokens which can be used to Authorise against an in-house API or an third party ERP product (used in organization) which support OIDC based authentication. Hope it's clear now
A note on the diagram is that the Authentication service could probably be built into the API Gateway - not sure if that would be better?
If you are planning to implement an API gateway, think twice. If things are small scale and if you think you can maintain it, then go ahead. But consider about API managers which could provide most of your required functionalities. I welcome you to read this article about WSO2 API manger and understand its capabilities (No I'm not working for them).
For example, that API manager has built in authentication handling mechanism for OAuth and OIDC. It can handle API authentication with simple set of configurations. With such solution you get rid of the requirement of implement everything.
What if you can't use an API manager and has to do it yourself
OpenID Connect is for authentication. Your application can validate the id token and authenticate end user. To access APIs through API Gateway, I think you should utilise Access token.
To validate the access token, you can use introspection endpoint of the identity provider. And to get user information, you can use user-info endpoint.
Once access token is validated, API gateway could create a session for a limited time (ideally to be less or equal to access token lifetime). Consequent requests should come with this session to accept by API gateway. Alternatively, you can still use validated access token. Since you validated it at the first call, you may cache for a certain time period thus avoiding round trips to validations.
To validate user details, permission and other grants, well you must wither bind user to a session or else associate user to access token from API gateway at token validation. I'm also not super clear about this as I have no idea on how your DB logic works.
First Appreciate your patience in writing a very valuable question in this forum
we too have same situation and problem
I want to go through ,as images are blocked in our company in detail
Was trying to draw paralles to similar one quoted in the book
Advance API In Practise - Prabath Siriwerdena [ page 269]Federating access to API's Chapter. Definitely worth reading of his works
API GW should invoke Token Exchange OAUTH2.0 Profile to IDP [ provided the IDP should support TOken Exchange profile for OAUTH 2.0
The Absence of API Gateway , will result in quite bespoke development
for Access Control for each API Check
you land up in having this check at each of the api or microservice [ either as library which does work for you as a reusable code]
definitely will become a choking point.]

What is the difference between the OAuth Authorization Code and Implicit workflows? When to use each one?

OAuth 2.0 has multiple workflows. I have a few questions regarding the two.
Authorization code flow - User logs in from client app, authorization server returns an authorization code to the app. The app then exchanges the authorization code for access token.
Implicit grant flow - User logs in from client app, authorization server issues an access token to the client app directly.
What is the difference between the two approaches in terms of security? Which one is more secure and why?
I don't see a reason why an extra step (exchange authorization code for token) is added in one work flow when the server can directly issue an Access token.
Different websites say that Authorization code flow is used when client app can keep the credentials secure. Why?
The access_token is what you need to call a protected resource (an API). In the Authorization Code flow there are 2 steps to get it:
User must authenticate and returns a code to the API consumer (called the "Client").
The "client" of the API (usually your web server) exchanges the code obtained in #1 for an access_token, authenticating itself with a client_id and client_secret
It then can call the API with the access_token.
So, there's a double check: the user that owns the resources surfaced through an API and the client using the API (e.g. a web app). Both are validated for access to be granted. Notice the "authorization" nature of OAuth here: user grants access to his resource (through the code returned after authentication) to an app, the app get's an access_token, and calls on the user's behalf.
In the implicit flow, step 2 is omitted. So after user authentication, an access_token is returned directly, that you can use to access the resource. The API doesn't know who is calling that API. Anyone with the access_token can, whereas in the previous example only the web app would (it's internals not normally accessible to anyone).
The implicit flow is usually used in scenarios where storing client id and client secret is not recommended (a device for example, although many do it anyway). That's what the the disclaimer means. People have access to the client code and therefore could get the credentials and pretend to become resource clients. In the implicit flow all data is volatile and there's nothing stored in the app.
I'll add something here which I don't think is made clear in the above answers:
The Authorization-Code-Flow allows for the final access-token to never reach and never be stored on the machine with the browser/app. The temporary authorization-code is given to the machine with the browser/app, which is then sent to a server. The server can then exchange it with a full access token and have access to APIs etc. The user with the browser gets access to the API only through the server with the token.
Implicit flow can only involve two parties, and the final access token is stored on the client with the browser/app. If this browser/app is compromised so is their auth-token which could be dangerous.
tl;dr don't use implicit flow if you don't trust the users machine to hold tokens but you do trust your own servers.
The difference between both is that:
In Implicit flow,the token is returned directly via redirect URL with "#" sign and this used mostly in javascript clients or mobile applications that do not have server side at its own, and the client does not need to provide its secret in some implementations.
In Authorization code flow, code is returned with "?" to be readable by server side then server side is have to provide client secret this time to token url to get token as json object from authorization server. It is used in case you have application server that can handle this and store user token with his/her profile on his own system, and mostly used for common mobile applications.
so it is depends on the nature of your client application, which one more secure "Authorization code" as it is request the secret on client and the token can be sent between authorization server and client application on very secured connection, and the authorization provider can restrict some clients to use only "Authorization code" and disallow Implicit
Which one is more secure and why?
Both of them are secure, it depends in the environment you are using it.
I don't see a reason why an extra step (exchange authorization code
for token) is added in one work flow when the server can directly
issue an Access token.
It is simple. Your client is not secure. Let's see it in details.
Consider you are developing an application against Instagram API, so you register your APP with Instagram and define which API's you need. Instagram will provide you with client_id and client_secrect
On you web site you set up a link which says. "Come and Use My Application". Clicking on this your web application should make two calls to Instagram API.
First send a request to Instagram Authentication Server with below parameters.
1. `response_type` with the value `code`
2. `client_id` you have get from `Instagram`
3. `redirect_uri` this is a url on your server which do the second call
4. `scope` a space delimited list of scopes
5. `state` with a CSRF token.
You don't send client_secret, You could not trust the client (The user and or his browser which try to use you application). The client can see the url or java script and find your client_secrect easily. This is why you need another step.
You receive a code and state. The code here is temporary and is not saved any where.
Then you make a second call to Instagram API (from your server)
1. `grant_type` with the value of `authorization_code`
2. `client_id` with the client identifier
3. `client_secret` with the client secret
4. `redirect_uri` with the same redirect URI the user was redirect back to
5. `code` which we have already received.
As the call is made from our server we can safely use client_secret ( which shows who we are), with code which shows the user have granted out client_id to use the resource.
In response we will have access_token
The implicit grant is similar to the authorization code grant with two distinct differences.
It is intended to be used for user-agent-based clients (e.g. single page web apps) that can’t keep a client secret because all of the application code and storage is easily accessible.
Secondly instead of the authorization server returning an authorization code which is exchanged for an access token, the authorization server returns an access token.
Please find details here
http://oauth2.thephpleague.com/authorization-server/which-grant/
Let me summarize the points that I learned from above answers and add some of my own understandings.
Authorization Code Flow!!!
If you have a web application server that act as OAuth client
If you want to have long lived access
If you want to have offline access to data
when you are accountable for api calls that your app makes
If you do not want to leak your OAuth token
If you don't want you application to run through authorization flow every time it needs access to data. NOTE: The Implicit Grant flow does not entertain refresh token so if authorization server expires access tokens regularly, your application will need to run through the authorization flow whenever it needs access.
Implicit Grant Flow!!!
When you don't have Web Application Server to act as OAuth Client
If you don't need long lived access i.e only temporary access to data is required.
If you trust the browser where your app runs and there is limited concern that the access token will leak to untrusted users.
Implicit grant should not be used anymore, see the IETF current best practices for details. https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-18#section-2.1.2
As an alternative use a flow with response type code; for clients without possibility to securely store client credentials the authorization code with PKCE flow should be your choice.
From practical perspective (What I understood), The main reason for having Authz code flow is :
Support for refresh tokens (long term access by apps on behalf of User), not supported in implicit: refer:https://www.rfc-editor.org/rfc/rfc6749#section-4.2
Support for consent page which is a place where Resource Owner can control what access to provide (Kind of permissions/authorization page that you see in google). Same is not there in implicit . See section : https://www.rfc-editor.org/rfc/rfc6749#section-4.1 , point (B)
"The authorization server authenticates the resource owner (via the user-agent) and establishes whether the resource owner grants or denies the client's access request"
Apart from that, Using refresh tokens, Apps can get long term access to user data.
There seem to be two key points, not discussed so far, which explain why the detour in the Authorization Code Grant Type adds security.
Short story: The Authorization Code Grant Type keeps sensitive information from the browser history, and the transmission of the token depends only on the HTTPS protection of the authorization server.
Longer version:
In the following, I'll stick with the OAuth 2 terminology defined in the RFC (it's a quick read): resource server, client, authorization server, resource owner.
Imagine you want some third-party app (= client) to access certain data of your Google account (= resource server). Let's just assume Google uses OAuth 2. You are the resource owner for the Google account, but right now you operate the third-party app.
First, the client opens a browser to send you to the secure URL of the Google authorization server. Then you approve the request for access, and the authorization server sends you back to the client's previously-given redirect URL, with the authorization code in the query string. Now for the two key points:
The URL of this redirect ends up in the browser history. So we don't want a long lived, directly usable access token here. The short lived authorization code is less dangerous in the history. Note that the Implicit Grant type does put the token in the history.
The security of this redirect depends on the HTTPS certificate of the client, not on Google's certificate. So we get the client's transmission security as an extra attack vector (For this to be unavoidable, the client needs to be non-JavaScript. Since otherwise we could transmit the authorization code via fragment URL, where the code would not go through the network. This may be the reason why Implicit Grant Type, which does use a fragment URL, used to be recommended for JavaScript clients, even though that's no longer so.)
With the Authorization Code Grant Type, the token is finally obtained by a call from the client to the authorization server, where transmission security only depends on the authorization server, not on the client.

Resources