What the OAuth?

Mine Kaya
BosphorusISS
Published in
8 min readNov 8, 2023

Hi, today I will try to explain OAuth topics, and follow Autharization Code Flow and try to access Google Apis through OAuth2 authentication.

Quick Background About Authorization

Almost all authorization processes needs user credentials, mostly as a username/password combination. There are some common words that we all here about, let’s go over on them.

Cookies : Maintains the ‘authenticated’ state between server and client. Stored on client.

Session : Records that server did for store client information, if client accesses the website again server only checks the session. Stored on server.

Token : A string generated by the server for checking credentials.

How cookie-based auth works and what are the drawbacks?

Basically think about a Html form, browser will send them to the server. After server authenticates the information, store that session value in the cookie. As long as session marked as authenticated, user can access the restricted resources.

The main drawback here is that we store some user’s private information on the browser. Cookies can be deleted, changed, even created without even visiting the website.

How token-based authentication works?

On token based client gives credentials again and receives a encrypted token from server. Encrypted string value is usually contains user’s details.

They usually added on the headers on request to access restricted resources.

Mostly used as JWT (JSON Web Tokens). JWT has 3 parts.

Example of JWT :

//JWT header
eyJhbGciOiJIUzI1NiIsInR5cCI5IkpXVC
//JWT payload
.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG8lIiwiaWF0IjoxNTE2MjM5MDIyfQ
//Signature
.SflKxwRJSMeKKF2QT4fwpMeJf36POk69JV_adQssw5c

I found this and its explain cookie-based and token-based authentication pretty well. As you can see the difference cookie based store info on client-side sends it every request but with token-based we encrypt the data and send it with jwt format on Authorization-Bearer header.

Why we need OAuth in the first place?

You can follow through any authorization process to manage your product or service but where users of one product would like to enable third-party websites or apps to access their information on the platform without share their credentials, cookie or token based authentication can not help with that, there comes OAuth.

What is OAuth?

OAuth is an industry-standard authorization protocol currently has two versions. OAuth 1.0 (rfc5849) OAuth 2.0 (rfc 6749).

Oauth allows users to share data with an application while keeping their usernames, passwords private.

Differences between them:

  • OAuth 2.0 has better support for non-browser applications (aka mobile apps)
  • OAuth 1.0 access tokens can live for 1+ year, but in v2 tokens can contain an expiration time, and also it offers refresh token which can be used to get new access token without asking credentials again.
  • OAuth 1.0 needs a signature on every API call but 2.0 uses TLS/SSL for communication.

Authorization Flows

There are 4 types of flow (/grant) used by the client to get an access token from resource owner.

  • Authorization Code
  • Implicit
  • Resource Owner Password Credentials
  • Client Credentials

I will follow Authorization Code flow in this example

Terminology

Before move further, let’s take quick look to words that used by Oauth. I will not try to use this fancy words for now because it getting a bit complicated to explain with them, but if you search more about the topic u will see them so it can be good to get familiar.

Resource Owner : This is end user (it can also be a machine)

Client: The app that requests access to a protected resource

Resource Server: Server that hosting protected resources. (API that we want to access)

Authorization server: Server that authenticates the Resource owner and give an access token after a successful authorization

User Agent : Agent used by the resource owner to interact with the client (like a browser or mobile app)

Keywords

This is the words that you should know.

  • Client Credentials : The client credentials (or other forms of client authentication) can be used as an authorization grant when the authorization scope is limited to the protected resources under the control of the client, or to protected resources previously arranged with the authorization server.
  • Access Token : Access tokens are credentials used to access protected resources. An access token is a string representing an authorization issued to the client. Tokens represent specific scopes and durations of access, granted by the resource owner
  • Refresh Token: Refresh tokens are credentials used to obtain access tokens. Refresh tokens are issued to the client by the authorization server and are used to obtain a new access token when the current access token becomes invalid or expires.
resource of the image

Authorization Code Flow

Authorization Code Flow exchanges authorization codes for tokens. For this exchange to work, your app must be server-side because you’re exchanging your app’s Client Secret which has to be stored securely in your client.

The Authorization Code grant type follows these steps:

  • The app opens a browser sending the user to the OAuth server.
  • The user approves the app’s request following an authorization prompt.
  • The user is redirected back to the app with an authorization code.
  • The app exchanges the authorization code for an access token.
  • And if you want refresh your access token you can do it with you refresh token.
resource of the gif

Using OAuth2 to Access Google API’S

Lets start to implement GmailAPI, following authorization code flow with Google OAuth 2.0.

Step 1 : Get OAuth2 credentials from the Google API

Open the Google Console and create a project, if you have already go to dashboard. And go to APIs and Services module.

From Credentials page click the create credentials and choose OAuth client Id. And you will be choosing Application type and give a name. And you will be declare your redirect Urls. As google mentioned on bottom of the titles, they are the paths that u will request the code and recieve the tokens.

Since that i will work on on local I typed localhost on both. But you can give your domain too.

And after you click the create they will shown as a pop-up, you can save them just in case.

Step 2: Define scopes of access granted by the user.

From Oauth consent screen you can add your scopes.

Scopes enable your app to only request access to the resources that it needs also enables users to control over the access they want to give.

Now we have our client credentials and scopes lets use them to get our authorization code.

Step 3: Get an access token from Google Authorization Server with Authorization Code

Now first move is sending a request to :

https://accounts.google.com/o/oauth2/v2/auth?
include_granted_scopes=true&
response_type=code&
redirect_uri={{your_redirect_url}&
client_id={{your_client_id}}m&
access_type=offline&
scope={{your_scopes}}

This will redirect us to classic google login window and after we select the account and give permissions to access defined scopes, google auth server will give response to redirect_url that we defined on console

Remember that with giving access_type=offline prompt you asking for refresh_token too.

The response inculed our authorization code , now we will exchange it with access_token on server side.

The reason for making this on server-side is you have to exchange your client_secret. And its important the make it secure.

We making a http request to: https://oauth2.googleapis.com/token




public async Task<TokenDto> GoogleAuthorize(string authorizationCode)
{
try
{
using (HttpClient client = new HttpClient())
{
var queryParameters = new System.Collections.Specialized.NameValueCollection
{
{ "client_id", _googleConfiguration.ClientId },
{ "client_secret", _googleConfiguration.ClientSecret },
{ "redirect_uri", _googleConfiguration.RedirectURI },
{ "scope", _googleConfiguration.Scopes },
{ "access_type", "offline" },
{ "prompt", "consent" },
{ "grant_type" , "authorization_code"},
{ "code", authorizationCode },

};

string url = "https://oauth2.googleapis.com/token" + ToQueryString(queryParameters);

HttpResponseMessage response = await client.PostAsync(url, null);

if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();

dynamic jsonObject = JsonConvert.DeserializeObject(responseContent);

string access_Token = jsonObject.access_token;
string refresh_token = jsonObject.refresh_token;
string id_token = jsonObject.id_token;
int expires_in = jsonObject.expires_in;

return new TokenDto { AccessToken = access_Token, RefreshToken = refresh_token };

}
else
{
var readAsStringAsync = response.Content.ReadAsStringAsync();
var message = readAsStringAsync.Result;
throw new InvalidCredentialsException(message);
}
}
}
catch (Exception ex)
{
throw new InvalidCredentialsException(ex.Message);
}
}

After this request we will have our access token, refresh roken and more. Id_token is includes information about user and expires_in will say when access token will expire.

Step 4 : Use tokens for making a request to the restricted APIs.

We define GoogleAuthorizationCodeFlow with our credentials and scopes:

        private GoogleAuthorizationCodeFlow flow;


public GoogleService(IOptions<GoogleConfiguration> googleConfiguration)
{
_googleConfiguration = googleConfiguration.Value;

flow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets
{
ClientId = _googleConfiguration.ClientId,
ClientSecret = _googleConfiguration.ClientSecret
},
Scopes = scopes
});
}

Now getting a UserCredential with accessToken and refreshToken from step 3.

     public UserCredential GetCredential(string? accessToken, string refreshToken)
{
var token = new TokenResponse
{
AccessToken = accessToken,
RefreshToken = refreshToken
};

var credential = new UserCredential(flow, Environment.UserName, token);

return credential;
}

After getting credentials I create GmailService instance.

I asked for gmail scopes on Step 2.

 public GmailService GetGmailService(string accessToken, string refreshToken)
{

var credential = GetCredential(accessToken, refreshToken);

var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "your_application_name",
});

return service;
}

Now you can list messages or send message behalf on user if you defined them on your scope.

Step 5 : Refresh your tokens, if you need it.

As I said on Step 1 you can refresh your access token with refres token, you will make a call too https://oauth2.googleapis.com/token again with changing grant_type

 public async Task<string> GetAccessToken(string refreshToken)
{
try
{
using (HttpClient client = new HttpClient())
{
var queryParameters = new System.Collections.Specialized.NameValueCollection
{
{ "client_id", _googleConfiguration.ClientId },
{ "client_secret", _googleConfiguration.ClientSecret },
{ "grant_type" , "refresh_token"},
{ "refresh_token", refreshToken },

};

string url = "https://oauth2.googleapis.com/token" + ToQueryString(queryParameters);

HttpResponseMessage response = await client.PostAsync(url, null);

if (response.IsSuccessStatusCode)
{
string responseContent = await response.Content.ReadAsStringAsync();

dynamic jsonObject = JsonConvert.DeserializeObject(responseContent);

string accessToken = jsonObject.access_token;
string id_token = jsonObject.id_token;
int expires_in = jsonObject.expires_in;

return accessToken;
}
else
{
var readAsStringAsync = response.Content.ReadAsStringAsync();
var message = readAsStringAsync.Result;
throw new InvalidCredentialsException(message);
}
}
}
catch (Exception ex)
{
throw new InvalidCredentialsException(ex.Message);
}

}

Step 6: Submit for brand verification

After your development process finished, you will apply for brand verification if your project runs on production. You can find related google doc, here.

If you don’t verify, this will show up every time when there is a user wants to connect your app.

Little suggestion here , I will highly recommend to read your scopes definitions. Some scopes also cover others, if there is unnecessary scope you will have to remove it on your verification process. And along to way this can take a lot of time, because of back and forward of mailing.

Thank you for reading, hope it helped you !

--

--