OAuth2

When I was working with Rakuten payment app , I embarked on a challenging project to enhance the security of a legacy payment app. The app had been using a token that never expired, posing a significant security risk. My mission was to implement OAuth 2 from the mobile Android app's perspective, ensuring the acquisition and refreshing of access tokens, handling token expiration seamlessly, and efficiently managing API calls. The server-side implementation had already been completed by another developer, and the tokens used were JWT tokens.

To implement OAuth 2 in the mobile app, below steps were followed:

  1. Integrating the necessary libraries and dependencies, including a JWT library to decode and verify the tokens.
  2. Implemention of a token management system within the app. This involved storing and securely managing the access token, refresh token, and their expiration times. Leveraged the device's secure storage mechanisms, such as the KeyStore on Android, to ensure the tokens were adequately protected.


One of the key challenge was handling token expiration. With the previous token that never expired, the app had been relying on continuous authentication sessions. However, with OAuth 2, access tokens have a limited lifespan, and managing their expiration became crucial. I implemented a mechanism to check the token's expiration before making an API call. If the token was expired, I used the refresh token to obtain a new access token from the server.

Another significant challenge was dealing with failed API calls due to token expiration. When an API call failed due to an expired token, I needed to capture the failed request, acquire a new access token using the refresh token, and automatically retry the failed request. This involved implementing request interception and handling, ensuring a seamless experience for the user. By leveraging the OkHttpClient library and its powerful interceptors, I achieved this functionality efficiently.

In the end, the implementation of OAuth 2 in the mobile app greatly enhanced the security of the payment application. The introduction of access token expiration, refresh token usage, and automated API call retries significantly reduced the potential risks associated with long-lived tokens. Users could now experience a more secure and seamless payment experience, knowing their sensitive information was protected by modern authentication mechanisms.


Let me share my study results of OAuth 2.0 below:

OAuth 2.0 has become the standard protocol for user authentication and authorization across various applications and platforms, including mobile apps. It provides a secure and standardized way for users to grant third-party applications limited access to their resources without sharing their credentials. This article aims to delve into OAuth 2.0 and its implementation in mobile apps.

OAuth 2.0 is a robust and widely adopted authorization framework for mobile app development. By leveraging OAuth 2.0, mobile apps can securely authenticate and authorize users, access protected resources, and interact with various third-party platforms. Understanding the OAuth 2.0 workflow and implementing the necessary security measures is crucial for building secure and user-friendly mobile apps.

What is OAuth 2.0?

OAuth 2.0 is an authorization framework that allows users to grant limited access to their resources (such as personal information or online accounts) to third-party applications without exposing their credentials. It provides a secure and standardized protocol for authorization and authentication.

OAuth 2.0 Roles:

OAuth 2.0 involves three primary roles:

a. Resource Owner: The resource owner is the end-user who owns the resources and can grant access to them.

b. Client: The client represents the application that seeks access to the resource owner's resources.

c. Authorization Server: The authorization server is responsible for authenticating the resource owner and issuing access tokens to the client.

Authorization Grant Types:

OAuth 2.0 supports various authorization grant types that define how clients can obtain access tokens. Some common grant types used in mobile app scenarios include:

a. Authorization Code: This flow is suitable for apps with a server-side component. The client redirects the user to the authorization server, which issues an authorization code. The client exchanges this code for an access token.

b. Implicit Grant: This flow is suitable for browser-based or mobile apps. The client directly receives an access token from the authorization server without an intermediate authorization code.

c. Resource Owner Password Credentials: In this flow, the client collects the user's credentials and directly exchanges them for an access token. It is typically used for trusted applications.

OAuth 2.0 Workflow in Mobile Apps:

Protocol Flow

     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

                     Figure 1: Abstract Protocol Flow        


Here's a step-by-step explanation of how OAuth 2.0 works in mobile apps:

(A)?The client requests authorization from the resource owner.?The authorization request can be made directly to the resource owner (as shown), or preferably indirectly via the authorization server as an intermediary.

(B)?The client receives an authorization grant, which is a credential representing the resource owner's authorization, expressed using one of four grant types defined in this specification or using an extension grant type.?The authorization grant type depends on the method used by the client to request authorization and the types supported by the authorization server.

(C)?The client requests an access token by authenticating with the authorization server and presenting the authorization grant.

(D)?The authorization server authenticates the client and validates the authorization grant, and if valid, issues an access token.

(E) The client requests the protected resource from the resource server and authenticates by presenting the access token.

(F)?The resource server validates the access token, and if valid,?serves the request.


Flow w.r.t Mobile app

Step 1: User Authentication

  • The user launches the mobile app and selects the option to sign in using a third-party account (e.g., Google, Facebook).
  • The mobile app redirects the user to the corresponding authorization server's login page.

Step 2: Authorization Grant

  • The user enters their credentials on the authorization server's login page.
  • The authorization server verifies the user's credentials and generates an authorization code or access token.

Step 3: Token Exchange

  • The mobile app receives the authorization code or access token.
  • The app securely sends this code or token to the authorization server.

Step 4: Access Token Retrieval

  • The authorization server validates the authorization code or token.
  • If valid, the server issues an access token to the mobile app.

Step 5: Resource Access

  • The mobile app includes the access token in subsequent API requests to the resource server.
  • The resource server verifies the access token and grants access to the requested resources.

In order to understand OAuth2 , we need to understand below

Authorization Grant:

An authorization grant is a credential issued by the resource owner (typically a user) to authorize a client application to access protected resources on their behalf. OAuth 2.0 defines several types of authorization grants that vary in terms of security and suitability for different scenarios. The most common types are:

  • Authorization Code: This grant type is commonly used in web and mobile applications. It involves the client application obtaining an authorization code from the authorization server, which is then exchanged for an access token.
  • Implicit: The implicit grant type is suitable for client-side applications or mobile apps where the client can't securely store a client secret. The access token is directly returned to the client without an intermediate authorization code exchange step.
  • Resource Owner Password Credentials: This grant type allows the client application to directly exchange the resource owner's username and password for an access token. It should be used only when there is a high level of trust between the client and the resource owner, such as when the client is a first-party application owned by the same entity as the authorization server.
  • Client Credentials: The client credentials grant type is used by confidential clients, such as server-side applications, to authenticate directly with the authorization server using their own credentials. The client is issued an access token based on its own identity and is not acting on behalf of a specific user.

Authorization Code:

The authorization code is a short-lived credential obtained by the client application through the authorization code grant type. It is used to exchange for an access token and sometimes a refresh token. The client includes the authorization code in a token request to the authorization server to prove that it has been authorized by the resource owner.

Client ID and Client Secret:

The client ID and client secret are credentials assigned to the client application by the authorization server during the registration process. The client ID identifies the client, while the client secret is a confidential value known only to the client and the authorization server. They are used to authenticate the client application during the authorization process.

Resource Owner Password Credentials:

Resource Owner Password Credentials grant type allows the client application to directly exchange the resource owner's username and password for an access token. The client includes the resource owner's credentials in the token request to the authorization server. However, this grant type should be used with caution and only in scenarios where the client application has a high level of trust and control over the resource owner's credentials.

Client Credentials:

The client credentials grant type is used by confidential clients, such as server-side applications, to authenticate directly with the authorization server. The client sends its own credentials (client ID and client secret) to the authorization server and receives an access token that represents the client's identity and permissions. This grant type is typically used when the client is not acting on behalf of a specific user but requires access to its own resources.


Bearer Authentication:

In token-based authentication, the term "Bearer" refers to the authentication scheme used to include the token in API requests. The Bearer scheme indicates that the token should be included in the "Authorization" header of the request using the format: "Authorization: Bearer <access_token>". The server then verifies the token and grants access to the requested resources if the token is valid.

Bearer authentication is a widely adopted approach due to its simplicity and ease of implementation. However, it's crucial to ensure the secure transmission and storage of tokens, as they grant access to protected resources. Proper measures should be taken, such as using HTTPS for communication and securely storing tokens on the client-side.

About the various types of Tokens used

Access Token:

An access token is a credential issued by the authorization server to the client application after successful authentication and authorization. It is used by the client to access protected resources on behalf of the user. The access token is usually short-lived and has an expiration time.

Example:

Let's consider a scenario where a mobile app integrates with a social media platform using OAuth 2.0. After the user authenticates and authorizes the mobile app to access their social media profile, the authorization server issues an access token to the mobile app. The app includes this access token in API requests to the social media platform's server to fetch the user's profile information or post on their behalf.


Example Access Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Fields in an Access Token:

  • Header: Contains information about the token type and the algorithm used for token signing (e.g., "alg" and "typ").
  • Payload/Claims: Contains information about the user and additional metadata. Common claims include "sub" (subject), "iss" (issuer), "exp" (expiration time), "aud" (audience), and custom claims.


Refresh Token:

A refresh token is a long-lived credential that is also issued by the authorization server along with the access token. It is used to obtain a new access token when the current access token expires. The refresh token is usually kept secure on the client-side and is not shared with the resource server.

Example:

Continuing with the previous example, when the access token obtained by the mobile app expires, instead of prompting the user to re-authenticate, the app can use the refresh token to request a new access token from the authorization server. This process occurs behind the scenes, providing a seamless user experience without requiring the user to log in again.

Example Refresh Token: Rt2ksjd3468FGd78gkf345jJFw

Fields in a Refresh Token:

A refresh token is often opaque, meaning that its internal structure and fields are not directly accessible or standardized. Its value is typically long and randomly generated. The refresh token is securely stored on the client-side and used to obtain a new access token when the current one expires.

ID Token:

An ID token is specific to the OpenID Connect (OIDC) protocol, which is built on top of OAuth 2.0. It is an optional token that contains identity information about the authenticated user. The ID token provides information such as the user's unique identifier, name, email address, and other user attributes. It is used for authentication purposes.

Example:

In a mobile app integrating with an OIDC provider, such as Google or Microsoft, the ID token is received alongside the access token and is typically used to authenticate the user within the app. The app can extract the user's email address or display their name based on the information provided in the ID token.

Example ID Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJhdWQiOiJpc3N1ZXIiLCJleHAiOjE1MTYyMzkwMjJ9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

Fields in an ID Token:

  • Header: Contains information about the token type and the algorithm used for token signing (e.g., "alg" and "typ").
  • Payload/Claims: Contains information about the user's identity and additional details. Common claims include "sub" (subject), "iss" (issuer), "exp" (expiration time), "aud" (audience), "iat" (issued at), and custom claims.


Difference between Access Token, Refresh Token, and ID Token:

Purpose:

  • Access Token: Used by the client to access protected resources on behalf of the user.
  • Refresh Token: Used to obtain a new access token when the current access token expires.
  • ID Token: Provides identity information about the authenticated user.

Lifespan:

  • Access Token: Typically short-lived and has an expiration time.
  • Refresh Token: Long-lived and is used to refresh the access token when it expires.
  • ID Token: Valid for the duration of the authentication session.

Usage:

  • Access Token: Sent in API requests to access protected resources on the resource server.
  • Refresh Token: Sent to the authorization server to obtain a new access token.
  • ID Token: Used for user authentication and to retrieve identity information about the user.

Scopes:

  • Access Token: Contains the requested scopes that define the permissions granted to the client.
  • Refresh Token: Typically does not include scopes since its purpose is to obtain a new access token.
  • ID Token: Does not include scopes but includes claims with user identity information.

OAuth 2.0 vs. OIDC:

  • Access Token and Refresh Token are concepts in OAuth 2.0 and can be used independently of OIDC.
  • ID Token is specific to the OIDC protocol and provides user identity information along with the access token.

Overall, access tokens and refresh tokens are used for authorization purposes, while the ID token is used for authentication and user identity information.


How to refresh the expired Access token

 +--------+                                           +---------------
  |        |--(A)------- Authorization Grant --------->|               |
  |        |                                           |               |
  |        |<-(B)----------- Access Token -------------|               |
  |        |               & Refresh Token             |               |
  |        |                                           |               |
  |        |                            +----------+   |               |
  |        |--(C)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(D)- Protected Resource --| Resource |   | Authorization |
  | Client |                            |  Server  |   |     Server    |
  |        |--(E)---- Access Token ---->|          |   |               |
  |        |                            |          |   |               |
  |        |<-(F)- Invalid Token Error -|          |   |               |
  |        |                            +----------+   |               |
  |        |                                           |               |
  |        |--(G)----------- Refresh Token ----------->|               |
  |        |                                           |               |
  |        |<-(H)----------- Access Token -------------|               |
  +--------+           & Optional Refresh Token        +---------------++        

(A)?The client requests an access token by authenticating with the authorization server and presenting an authorization grant.

(B)?The authorization server authenticates the client and validates the authorization grant, and if valid, issues an access token and a refresh token.

(C)?The client makes a protected resource request to the resource server by presenting the access token.

(D)?The resource server validates the access token, and if valid, serves the request.

(E)?Steps (C) and (D) repeat until the access token expires.?If theclient knows the access token expired, it skips to step (G); otherwise, it makes another protected resource request.

(F)?Since the access token is invalid, the resource server returns an invalid token error.

(G)?The client requests a new access token by authenticating with the authorization server and presenting the refresh token.?The client authentication requirements are based on the client type and on the authorization server policies.

(H)?The authorization server authenticates the client and validates the refresh token, and if valid, issues a new access token (and, optionally, a new refresh token).

Example code

Example code to check if an access token has expired and obtain a new token based on a refresh token, you typically need to validate the expiration time of the access token and make a request to the token endpoint using the refresh token.

import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import java.io.IOException

class TokenManager {

? ? private val client: OkHttpClient

? ? private var accessToken: String? = null
? ? private var refreshToken: String? = null

? ? init {
? ? ? ? val loggingInterceptor = HttpLoggingInterceptor().apply {
? ? ? ? ? ? level = HttpLoggingInterceptor.Level.BODY
? ? ? ? }

? ? ? ? client = OkHttpClient.Builder()
? ? ? ? ? ? .addInterceptor(loggingInterceptor)
? ? ? ? ? ? .build()
? ? }

? ? fun makeApiCall(url: String) {
? ? ? ? if (accessToken != null && !isAccessTokenExpired()) {
? ? ? ? ? ? // Access token is valid, make the API call
? ? ? ? ? ? val request = createRequest(url, accessToken!!)
? ? ? ? ? ? executeApiCall(request)
? ? ? ? } else if (refreshToken != null) {
? ? ? ? ? ? // Access token has expired, use the refresh token to obtain a new token
? ? ? ? ? ? refreshToken(refreshToken!!)
? ? ? ? } else {
? ? ? ? ? ? // No access token or refresh token available, prompt the user to log in
? ? ? ? ? ? // and obtain tokens through the authentication flow
? ? ? ? }
? ? }

? ? private fun isAccessTokenExpired(): Boolean {
? ? ? ? // Implement the logic to check the expiration time of the access token
? ? ? ? // Compare the current time with the expiration time stored in the token
? ? ? ? // Return true if the token has expired, false otherwise
? ? }

? ? private fun createRequest(url: String, token: String): Request {
? ? ? ? return Request.Builder()
? ? ? ? ? ? .url(url)
? ? ? ? ? ? .header("Authorization", "Bearer $token")
? ? ? ? ? ? .build()
? ? }

? ? private fun executeApiCall(request: Request) {
? ? ? ? client.newCall(request).enqueue(object : Callback {
? ? ? ? ? ? override fun onFailure(call: Call, e: IOException) {
? ? ? ? ? ? ? ? // Handle failure
? ? ? ? ? ? }

? ? ? ? ? ? override fun onResponse(call: Call, response: Response) {
? ? ? ? ? ? ? ? if (response.isSuccessful) {
? ? ? ? ? ? ? ? ? ? val responseBody = response.body?.string()
? ? ? ? ? ? ? ? ? ? // Process the API response
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? // Handle non-successful response
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? })
? ? }

? ? private fun refreshToken(refreshToken: String) {
? ? ? ? val requestBody = FormBody.Builder()
? ? ? ? ? ? .add("grant_type", "refresh_token")
? ? ? ? ? ? .add("refresh_token", refreshToken)
? ? ? ? ? ? .build()

? ? ? ? val request = Request.Builder()
? ? ? ? ? ? .url("https://example.com/token") // Replace with the token endpoint URL
? ? ? ? ? ? .post(requestBody)
? ? ? ? ? ? .build()

? ? ? ? client.newCall(request).enqueue(object : Callback {
? ? ? ? ? ? override fun onFailure(call: Call, e: IOException) {
? ? ? ? ? ? ? ? // Handle failure
? ? ? ? ? ? }

? ? ? ? ? ? override fun onResponse(call: Call, response: Response) {
? ? ? ? ? ? ? ? if (response.isSuccessful) {
? ? ? ? ? ? ? ? ? ? val responseBody = response.body?.string()
? ? ? ? ? ? ? ? ? ? // Parse the response body to obtain the new access token and refresh token
? ? ? ? ? ? ? ? ? ? accessToken = parseAccessToken(responseBody)
? ? ? ? ? ? ? ? ? ? refreshToken = parseRefreshToken(responseBody)

? ? ? ? ? ? ? ? ? ? // Store the new tokens securely for future use

? ? ? ? ? ? ? ? ? ? // Make the API call with the new access token
? ? ? ? ? ? ? ? ? ? val apiRequest = createRequest(url, accessToken!!)
? ? ? ? ? ? ? ? ? ? executeApiCall(apiRequest)
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? // Handle non-successful response
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? })
? ? }

? ? private fun parseAccessToken(responseBody: String?): String {
? ? ? ? // Implement parsing logic to extract the new access token from the response body
? ? }

? ? private fun parseRefreshToken(responseBody: String?): String {
? ? ? ? // Implement parsing logic to extract the new refresh token from the response body
? ? }
}        

In the above example:

  1. The makeApiCall function is responsible for checking if the access token is valid and making the API call. If the access token is valid, it creates a request with the token and executes the API call. If the access token has expired, it calls the refreshToken function.
  2. The isAccessTokenExpired function checks the expiration time of the access token. You need to implement the logic to compare the current time with the expiration time stored in the token and return true if the token has expired.
  3. The refreshToken function makes a request to the token endpoint using the refresh token. It creates a request with the necessary form parameters (grant type and refresh token) and executes the request. Upon a successful response, it parses the new access token and refresh token from the response body, stores them securely, and makes the API call again with the new access token.
  4. The parseAccessToken and parseRefreshToken functions are placeholders for the logic to extract the new access token and refresh token from the response body. You need to implement the parsing logic based on the response format of the token endpoint.

Remember to replace the placeholder URLs, implement the token parsing logic, and handle any additional error scenarios based on your specific requirements and the token endpoint's behavior.


What happens if the refresh token is also expired from mobile app POV

If the refresh token is also expired, you will not be able to obtain a new access token using the refresh token. The expiration of the refresh token typically depends on the server-side implementation and the token's configured expiration time.

In such a case, the user will need to go through the authentication flow again to obtain a new set of tokens. This may involve re-authenticating the user, either by providing their credentials or through another authentication mechanism.

Here's what typically happens when the refresh token is expired:

  1. The application attempts to use the expired refresh token to obtain a new access token.
  2. The server validates the refresh token and determines that it has expired.
  3. The server responds with an error indicating that the refresh token is expired.
  4. The application receives the error response and realizes that it cannot obtain a new access token using the expired refresh token.
  5. The application prompts the user to re-authenticate or login again.
  6. The user goes through the authentication flow, providing the necessary credentials or using another authentication mechanism.
  7. Upon successful authentication, the server issues a new set of tokens, including a new access token and refresh token.
  8. The application receives the new tokens and securely stores them for future use.
  9. The application can now use the new access token to make authenticated requests to protected resources.

It's important to handle the scenario where both the access token and refresh token have expired gracefully in your application. Providing appropriate feedback to the user and guiding them through the re-authentication process can help maintain a smooth user experience.


Securing OAuth 2.0 in Mobile Apps:

To ensure the security of OAuth 2.0 implementation in mobile apps, consider the following best practices:

  • Use secure communication protocols such as HTTPS to transmit tokens and sensitive data.
  • Implement token expiration and refresh mechanisms to prevent unauthorized access.
  • Store tokens securely on the client device and utilize secure storage options.
  • Implement proper error handling and error messages to avoid exposing sensitive information.
  • Regularly update mobile app libraries and frameworks to address any security vulnerabilities.

Advantages of OAuth 2.0:

  1. Enhanced Security: OAuth 2.0 provides a secure way to grant limited access to resources without sharing user credentials. It ensures that third-party applications only receive access tokens, reducing the risk of unauthorized access to user accounts.
  2. User Convenience: Users can easily authenticate and authorize third-party applications without the need to create separate credentials for each service. It simplifies the login process and improves user experience.
  3. Standardization: OAuth 2.0 is a widely adopted industry standard, which means it is well-documented, has extensive community support, and offers interoperability across various platforms and applications.
  4. Scalability: OAuth 2.0 allows users to grant access to their resources to multiple applications simultaneously, providing scalability and flexibility.

Disadvantages of OAuth 2.0:

  1. Complexity: Implementing OAuth 2.0 can be complex, especially for developers who are new to the protocol. It requires a good understanding of the workflow, grant types, and security considerations.
  2. Token Management: Managing access tokens and ensuring their secure storage can be challenging. Developers need to carefully handle token expiration, refresh, and revocation to maintain security.
  3. Dependency on Third-Party Authorization Servers: OAuth 2.0 relies on the availability and security of third-party authorization servers. If an authorization server experiences downtime or is compromised, it can impact the functionality and security of the mobile app.

Suitable Scenarios to Use OAuth 2.0:

  1. Third-Party Integrations: When developing mobile apps that need to access resources from popular platforms like social media networks, email providers, or cloud storage services, OAuth 2.0 simplifies the integration process.
  2. User-Managed Access: OAuth 2.0 is ideal for scenarios where users want granular control over the permissions they grant to third-party applications. It allows users to revoke access at any time, maintaining control over their data.
  3. Single Sign-On (SSO): OAuth 2.0 can be used for implementing SSO across multiple mobile apps. Users can sign in once and then seamlessly access other apps without re-entering their credentials.

Suitable Scenarios Not to Use OAuth 2.0:

  1. High-Security Applications: If a mobile app requires a higher level of security, such as handling highly sensitive or classified information, a more stringent authentication mechanism, such as multi-factor authentication or custom protocols, may be more appropriate.
  2. Limited Resource Access: If a mobile app only needs access to a limited set of resources within its own ecosystem, implementing a custom authentication and authorization mechanism might be simpler and more efficient than using OAuth 2.0.

Alternatives to OAuth 2.0:

OpenID Connect (OIDC) is an alternative protocol built on top of OAuth 2.0 that provides authentication capabilities along with authorization. OIDC adds an ID token to the OAuth 2.0 flow, allowing the client to obtain identity information about the user. It provides a standardized way to authenticate users while preserving the advantages of OAuth 2.0.

OIDC is considered more recent and has gained popularity due to its support for user authentication and user information retrieval in a single protocol. It simplifies the integration of identity providers and enhances security by validating the identity of the user in addition to authorizing access to resources.

In terms of security and convenience, both OAuth 2.0 and OIDC have their strengths, and the choice between them depends on the specific requirements of the mobile app and the desired user experience.


Kotlin example code using the OkHttp library to implement OAuth 2.0 from a mobile app side and make API calls:

In the below example, the OAuthApiClient class encapsulates the logic for obtaining an access token using the Resource Owner Password Credentials grant type and making API calls with the obtained access token. The login function sends a POST request to the token endpoint with the user's credentials, client ID, and client secret to obtain the access token and refresh token. The makeApiCall function demonstrates how to make authenticated API calls by including the access token in the Authorization header.

Note: This is a basic example, and in a real-world scenario, We should handle token expiration, token storage, token refresh, error handling, and other security considerations. Additionally, make sure to replace the placeholder URLs and implement the necessary parsing logic according to your OAuth 2.0 provider's

import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import java.io.IOException

// Encapsulates the OAuth 2.0 client functionality.
class OAuthApiClient {

? ? private val client: OkHttpClient //  will be used to make HTTP requests.

? ? init {
? ? ? ? val loggingInterceptor = HttpLoggingInterceptor().apply {
? ? ? ? ? ? level = HttpLoggingInterceptor.Level.BODY
            //  configuring it to log request and response bodies.
? ? ? ? }

? ? ? ? client = OkHttpClient.Builder()
? ? ? ? ? ? .addInterceptor(loggingInterceptor)
? ? ? ? ? ? .build()
? ? }

? ? // Function to handle user login & obtain access token & refresh token
? ? fun login(username: String, password: String, clientId: String, clientSecret: String) {
? ? ? ? val requestBody = FormBody.Builder()
? ? ? ? ? ? .add("grant_type", "password")
? ? ? ? ? ? .add("username", username)
? ? ? ? ? ? .add("password", password)
? ? ? ? ? ? .build()
// The above creates a FormBody.Builder to build the request body for the login request.

? ? ? ? val request = Request.Builder()
? ? ? ? ? ? .url("https://example.com/token") // Replace with the token endpoint URL
? ? ? ? ? ? .post(requestBody)
? ? ? ? ? ? .header("Authorization", createBasicAuthHeader(clientId, clientSecret))
? ? ? ? ? ? .build()

? ? ? ? client.newCall(request).enqueue(object : Callback {
? ? ? ? ? ? override fun onFailure(call: Call, e: IOException) {
? ? ? ? ? ? ? ? // Handle failure
? ? ? ? ? ? }

? ? ? ? ? ? override fun onResponse(call: Call, response: Response) {
? ? ? ? ? ? ? ? if (response.isSuccessful) {
? ? ? ? ? ? ? ? ? ? val responseBody = response.body?.string()
? ? ? ? ? ? ? ? ? ? // Parse the response body to obtain the access token and refresh token
? ? ? ? ? ? ? ? ? ? val accessToken = parseAccessToken(responseBody)
? ? ? ? ? ? ? ? ? ? val refreshToken = parseRefreshToken(responseBody)


? ? ? ? ? ? ? ? ? ? // Store the tokens securely for future use
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? // Handle non-successful response
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? })
? ? }

? ? // Function to make API call with the obtained access token
? ? fun makeApiCall(url: String, accessToken: String) {
? ? ? ? val request = Request.Builder()
? ? ? ? ? ? .url(url)
? ? ? ? ? ? .header("Authorization", "Bearer $accessToken")
? ? ? ? ? ? .build()

? ? ? ? client.newCall(request).enqueue(object : Callback {
? ? ? ? ? ? override fun onFailure(call: Call, e: IOException) {
? ? ? ? ? ? ? ? // Handle failure
? ? ? ? ? ? }

? ? ? ? ? ? override fun onResponse(call: Call, response: Response) {
? ? ? ? ? ? ? ? if (response.isSuccessful) {
? ? ? ? ? ? ? ? ? ? val responseBody = response.body?.string()
? ? ? ? ? ? ? ? ? ? // Process the API response
? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? // Handle non-successful response
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? })
? ? }

? ? // Function to create the Basic Authentication header with client ID and client secret
? ? private fun createBasicAuthHeader(clientId: String, clientSecret: String): String {
? ? ? ? val credentials = "$clientId:$clientSecret"
? ? ? ? val base64Credentials = credentials.toByteArray().encodeBase64()
? ? ? ? return "Basic $base64Credentials"
? ? }

? ? // Extension function to encode a ByteArray to Base64
? ? private fun ByteArray.encodeBase64(): String {
? ? ? ? return java.util.Base64.getEncoder().encodeToString(this)
? ? }

? ? // Function to parse the access token from the response body
? ? private fun parseAccessToken(responseBody: String?): String {
? ? ? ? // Implement parsing logic to extract the access token from the response body
? ? }

? ? // Function to parse the refresh token from the response body
? ? private fun parseRefreshToken(responseBody: String?): String {
? ? ? ? // Implement parsing logic to extract the refresh token from the response body
? ? }
}        


--------------------------------------------------------------------------------------------

Although I didn't work on OIDC , let me share my study results with you:

OpenID Connect (OIDC)

OpenID Connect (OIDC) is an authentication protocol built on top of OAuth 2.0. It provides a standardized way to obtain identity information about the authenticated user, in addition to the authorization capabilities of OAuth 2.0. OIDC allows applications to authenticate users and receive information about them from an identity provider (IdP) in a secure and interoperable manner.

Key Components of OpenID Connect:

Identity Provider (IdP):

The IdP is a trusted service that authenticates users and issues identity tokens. Popular examples of IdPs include Google, Facebook, Microsoft, and Okta.

Client Application:

The client application is the application that wants to authenticate users and obtain identity information. It interacts with both the IdP and the user.

Authorization Server:

The authorization server is responsible for verifying the user's identity and issuing tokens. In OIDC, the authorization server is often combined with the IdP.

ID Token:

The ID token is a JSON Web Token (JWT) issued by the authorization server after successful user authentication. It contains information about the user's identity, such as their unique identifier, name, email address, and other user attributes. The ID token is digitally signed by the authorization server and can be used by the client application to verify the user's identity.

Discovery Endpoint:

The discovery endpoint is a URL provided by the authorization server that allows the client application to discover the necessary endpoints and configuration details, such as the authorization endpoint and token endpoint.

OpenID Connect Workflow:

Discovery:

The client application discovers the OIDC endpoints and configuration details by making a request to the discovery endpoint provided by the authorization server.

Authorization Request:

The client initiates the authentication process by redirecting the user to the authorization endpoint. The request includes parameters such as client ID, redirect URL, requested scopes, and the desired response type (usually "code" or "id_token").

User Authentication:

The user is redirected to the authorization server's login page, where they enter their credentials to authenticate.

Authorization Grant:

After successful authentication, the authorization server generates an authorization code or an ID token, depending on the response type specified in the authorization request.

Token Request:

The client application exchanges the authorization code for an access token, ID token, or both by making a request to the token endpoint. The request includes the authorization code, client ID, client secret (if applicable), and redirect URL.

Token Validation and User Information:

The client verifies the authenticity of the received ID token by validating the signature and other JWT claims. It can then extract the user's identity information from the ID token.

Resource Access:

The client can use the obtained ID token to authenticate the user and access protected resources on behalf of the user. Additionally, the client can also use the access token obtained through the token request to access APIs protected by OAuth 2.0.

Benefits of OpenID Connect:

  1. Single Sign-On (SSO): OIDC enables SSO across multiple applications. Once a user is authenticated with the IdP, subsequent authentication requests to other applications can be seamlessly handled without requiring the user to re-enter their credentials.
  2. User Identity Information: OIDC provides identity information about the user in the form of ID tokens. Applications can utilize this information to personalize the user experience, provide personalized content, or tailor functionality based on the user's profile.
  3. Standardization: OIDC is an industry-standard protocol, ensuring interoperability between different identity providers and client applications. It simplifies the integration process and allows developers to leverage existing OIDC libraries and frameworks.
  4. Enhanced Security: OIDC enhances the security of user authentication by leveraging OAuth 2.0's security features, such as secure token exchange, token validation


Modern applications often use a combination of OAuth 2.0 and OpenID Connect (OIDC) protocols together. OAuth 2.0 primarily handles the authorization aspect, allowing applications to obtain access to protected resources on behalf of the user, while OIDC provides authentication capabilities in addition to authorization.

The main reasons for the adoption of OAuth 2.0 and OIDC in modern applications are:

  1. Security: OAuth 2.0 and OIDC protocols have undergone extensive security reviews and have been widely adopted, making them mature and well-tested frameworks. They provide secure methods for user authentication and authorization, reducing the risk of unauthorized access to resources.
  2. Standardization: OAuth 2.0 and OIDC are industry standards supported by a large community. Their standardized protocols enable interoperability across different platforms and applications. Developers can leverage existing libraries and frameworks that provide OAuth 2.0 and OIDC support, streamlining the development process.
  3. User Experience: OIDC enhances the user experience by providing a seamless and familiar authentication flow. Users can authenticate through a trusted identity provider (such as Google, Facebook, or Microsoft) without needing to create separate credentials for each application. This improves convenience and reduces the burden of remembering multiple usernames and passwords.
  4. Single Sign-On (SSO): OIDC enables single sign-on functionality, allowing users to authenticate once and gain access to multiple applications without the need for repeated authentication. This simplifies the login process for users and enhances usability.
  5. User Identity Information: OIDC provides ID tokens, which include user identity information, such as name, email address, and other user attributes. This information can be utilized by the application to personalize the user experience or tailor functionality based on the user's profile.

It's important to note that while OAuth 2.0 and OIDC are widely used and provide robust security and user experience benefits, the choice of protocols ultimately depends on the specific requirements and needs of the application. In some cases, applications may still rely solely on OAuth 2.0 for authorization if authentication is handled separately or using a custom authentication mechanism.

----------------------------------------------------------------

I used OkHttp for my project, below is my study results.

OkHttp

OkHttp is a popular and efficient HTTP client library for Android and Java applications. Developed by Square, OkHttp simplifies network communication, providing a robust set of features and easy-to-use APIs. In this article, we will explore how OkHttp works and learn how to integrate it into your projects.


OkHttp is built on top of the Java HttpURLConnection API and offers significant improvements in terms of performance, ease of use, and extensibility. It provides a simple yet powerful API for making HTTP requests and handling responses asynchronously. OkHttp supports features like connection pooling, transparent gzip compression, request/response interception, and much more.

Integration:

To get started with OkHttp, you need to add the library as a dependency in your project. If you're using Gradle, add the following line to your module's build.gradle file:

implementation 'com.squareup.okhttp3:okhttp:4.9.1'         

Once the dependency is added, you can start using OkHttp in your code.

Making Simple Requests:

To make a basic HTTP request with OkHttp, you'll typically follow these steps:

a. Create an instance of OkHttpClient:

val client = OkHttpClient()         

b. Create a Request object:

val request = Request.Builder()
    .url("https://api.example.com/data")
    .build()        

c. Execute the request:

val response = client.newCall(request).execute()         

d. Handle the response:

if (response.isSuccessful) {
? ? val responseBody = response.body?.string()
? ? // Process the response
} else {
? ? // Handle error
}        


Asynchronous Requests:

OkHttp also provides support for making asynchronous requests, allowing you to perform network operations without blocking the main thread. This is crucial for ensuring a smooth user experience in mobile applications. Here's an example:

val request = Request.Builder()
? ? .url("https://api.example.com/data")
? ? .build()

client.newCall(request).enqueue(object : Callback {
? ? override fun onFailure(call: Call, e: IOException) {
? ? ? ? // Handle failure
? ? }

? ? override fun onResponse(call: Call, response: Response) {
? ? ? ? if (response.isSuccessful) {
? ? ? ? ? ? val responseBody = response.body?.string()
? ? ? ? ? ? // Process the response asynchronously
? ? ? ? } else {
? ? ? ? ? ? // Handle non-successful response
? ? ? ? }
? ? }
})        

Advanced Features:

OkHttp offers several advanced features to enhance your networking capabilities:

a. Request/Response Interception: OkHttp allows you to intercept and modify requests and responses using interceptors. This enables you to add headers, log requests, cache responses, and perform various transformations.

b. Connection Pooling: OkHttp automatically manages connection reuse and pooling, improving performance by reducing the overhead of establishing new connections for subsequent requests.

c. Request Body and Multipart: OkHttp supports sending different types of request bodies, including form data, JSON payloads, and multipart requests with file uploads.

d. Customization and Extensions: OkHttp is highly extensible, allowing you to customize its behavior through interceptors, event listeners, and network configurations. Additionally, you can integrate OkHttp with other libraries like Retrofit for seamless API communication.


Thanks for reading , please comment if you have any !


Referance :

RFC 6749 - The OAuth 2.0 Authorization Framework (ietf.org)

Certificate and Public Key Pinning | OWASP Foundation

OkHttpClient.Builder (OkHttp 3.14.0 API) (square.github.io)

JSON Web Token - JWS JWT JWE with practical examples (carcano.ch)

An Introduction to OAuth 2 | DigitalOcean

要查看或添加评论,请登录

Amit Nadiger的更多文章

  • List of C++ 17 additions

    List of C++ 17 additions

    1. std::variant and std::optional std::variant: A type-safe union that can hold one of several types, useful for…

  • List of C++ 14 additions

    List of C++ 14 additions

    1. Generic lambdas Lambdas can use auto parameters to accept any type.

    6 条评论
  • Passing imp DS(vec,map,set) to function

    Passing imp DS(vec,map,set) to function

    In Rust, we can pass imp data structures such as , , and to functions in different ways, depending on whether you want…

  • Atomics in C++

    Atomics in C++

    The C++11 standard introduced the library, providing a way to perform operations on shared data without explicit…

    1 条评论
  • List of C++ 11 additions

    List of C++ 11 additions

    1. Smart Pointers Types: std::unique_ptr, std::shared_ptr, and std::weak_ptr.

    2 条评论
  • std::lock, std::trylock in C++

    std::lock, std::trylock in C++

    std::lock - cppreference.com Concurrency and synchronization are essential aspects of modern software development.

    3 条评论
  • std::unique_lock,lock_guard, & scoped_lock

    std::unique_lock,lock_guard, & scoped_lock

    C++11 introduced several locking mechanisms to simplify thread synchronization and prevent race conditions. Among them,…

  • Understanding of virtual & final in C++ 11

    Understanding of virtual & final in C++ 11

    C++ provides powerful object-oriented programming features such as polymorphism through virtual functions and control…

  • Importance of Linux kernal in AOSP

    Importance of Linux kernal in AOSP

    The Linux kernel serves as the foundational layer of the Android Open Source Project (AOSP), acting as the bridge…

    1 条评论
  • AOSP

    AOSP

    Android System Development AOSP stands for the Android Open Source Project. Its the foundation of the Android operating…

社区洞察

其他会员也浏览了