# SOFA - Simple OAuth 2.0 Framework for Authentication (Freeware)

This class implements a small and easy to use framework to support Java applications with OAuth 2.0 for machine-to-machine (M2M) or service-to-service authentication.

<a href="/pages/xBnpiZe1ibGY6x056Shb" class="button primary">Free Download</a>

{% hint style="info" %}
Follow development at Mastodon [#JavaSOFA](https://swiss.social/tags/javasofa)
{% endhint %}

#### Example code (Microsoft 365 Authentication)

```java
import ch.k43.tools.SOFA;

public class SOFATest {

   public static void main(String[] args) {

      // Create SOFA object
      SOFA sofa = new SOFA(
         "https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2/v2.0/token",   // Authorization Server with Azure Tenant ID
         "https://outlook.office365.com/.default");						  // Authentication Scope
		
      // Authenticate with client credentials
      if (!sofa.authenticateWithClientCredentials(
         "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",					          // Client ID (Application ID)
         "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) {						  // Client secret (Value)
         System.out.println("Authentication failed <" + sofa.getErrorMessage() + ">");
         return;
      };

      // Show the ready-to-use HTTP request header
      System.out.println("HTTP Header <" + sofa.getHttpAuthorizationHeader() + ">");
   }
}
```

#### **Console Output**

```
HTTP Header <Authorization: Bearer ey...jw>
```

#### Key Points

* Requires Java version 1.8 or higher.
* Uses plain HTTP protocol to implement OAuth 2.0 client calls. Only grant types which do not require any user interactions are supported (`client_credentials` and `password)`.
* Once authenticated at the OAuth 2.0 authorization server, `getAccessToken()` returns the current access token or transparently calls the authorization server to obtain a new access token, if it is expired.
* All confidential data used in this class is stored in temporary, volatile memory (RAM) protected by AES-256 encryption.
* The standard Java Logger framework (not the Apache Log4j) is supported by writing log entries with `Level.FINE` and `Level.WARNING`. Logging is enabled by adding a configuration file `SOFA-Logging.properties` which is read from the current directory (see [Logging / Debugging](/quick-start/logging-debugging)). No confidential data is written to the log.

{% hint style="warning" %}
Use this class only in trusted environments, since the calling application need to pass confidential data (e.g. client secret and/or user password) to the SOFA class for authentication.
{% endhint %}

### **Author**

This framework was created to help implementing projects which required the use of OAuth 2.0 authentication. If you encounter any issue or if you have a suggestion, please let me know.

You may contact me via my email address <andy.brunner@k43.ch>.

### **Freeware / Unlicense**

SOFA is [freeware](https://en.wikipedia.org/wiki/Freeware) and [unlicensed](https://en.wikipedia.org/wiki/Unlicense). It was created with love and passion in the beautiful country of 🇨🇭 Switzerland. This software shall be used for Good not Evil. As far as I know, no animal was harmed in the making of this software 😊

### **Credits**

Photo by [Konstantin Evdokimov](https://unsplash.com/@constantinevdokimov?utm_source=unsplash\&utm_medium=referral\&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/s/photos/key?utm_source=unsplash\&utm_medium=referral\&utm_content=creditCopyText)


# Downloads

Version history

### In Development

* getHttpResponseHeaders: Fixed HTTP response header Property

### Version 1.0.1 (2023-06-24)

{% file src="/files/JGwRKDyPy6SqDFrq75oN" %}

* Add HTTP header "Connection: close"
* Add used certificate chain to debug log

### Version 1.0.0 (2022-10-19)

{% file src="/files/T2WqtSpdNcP4UD5YXN1D" %}

* First formal release
* Minor debugging text updates

### Version 0.9.5 (2022-09-04)

{% file src="/files/i0zADUVJ927BDBJ76Mf3" %}

* Remove OAuth Provider Identifier (shortcuts für predefined OAuth providers)
* Update JavaDoc

### Version 0.8.1 (2022-08-19)

{% file src="/files/W6Op30IKP76U7a0Nws8M" %}

* Change `password` grant type to use basic authentication (HTTP authorization header)
* Include JSONObject.jar in SOFA.jar (single distribution package)

### Version 0.8.0 (2022-02-27 Beta 1 Version)

{% file src="/files/9qOLBzvUnxQyEebwMrrs" %}
Download Version 0.8.0
{% endfile %}

* **Please send any feedback to** [**andy.brunner@k43.ch**](mailto:andy.brunner@k43.ch)
* First public beta Version

### Version 0.7.0 (2022-02-26 Alpha 3 Version)

* Last pre beta version

### Version 0.6.0 (2022-02-25 Alpha 2 Version)

* [SOFA product](https://sofa.k43.ch/) website added&#x20;
* [SOFA JavaDoc](https://andybrunner.github.io/SOFA/ch/k43/tools/SOFA.html)Ve webseite added
* `getHttpResponseTimeMs()` added
* `setHttpTimeoutSec()` added

### Version 0.5.0 (2022-02-22 Alpha 1 Version)

* Proof of concept
* Successful testing with Microsoft Azure authorization server


# Installation

Installation Steps

* Download and extract the [SOFA distribution package](/quick-start/downloads). It consists of one JAR files with the Java classes.
* Add the files `SOFA.jar`to your Java classpath, e.g.

```bash
java -cp .:../lib/SOFA.jar 
```

* Import the SOFA class in your code, e.g.

```java
import ch.k43.tools.SOFA;
```


# Logging / Debugging

The SOFA Java class has a builtin, detailed logging funtion to help finding and diagnosing any issue you may encounter.

To enable the Java Logger framework, you need to add a Logger properties file `SOFA-Logging.properties` in the current directory of your running application.

#### **SOFA-Logging.properties Example**

```properties
# SOFA - Simple OAuth 2.0 Framework for Authentication - Logging configuration file
#
# Notes:
# - The SOFA class only uses logging level FINE (for debugging) and WARNING (for errors)
# - To disable logging, comment out all "handlers" properties or remove/rename this configuration file)

# Logging level for the SOFA class
SOFA.level                                  = FINE

# Specify where the logging output should go
#handlers                                   = java.util.logging.ConsoleHandler
#handlers                                   = java.util.logging.FileHandler
handlers	                            = java.util.logging.ConsoleHandler, java.util.logging.FileHandler

# Logging output format, e.g. "2022-01-27T16:44:00.322 FINE        SOFA Version ..."
java.util.logging.SimpleFormatter.format    = %1$tFT%1$tT.%1$tL %4$-11s %5$s %6$s %n

# Define logging output to system console
java.util.logging.ConsoleHandler.level      = ALL
java.util.logging.ConsoleHandler.formatter  = java.util.logging.SimpleFormatter

# Define logging output to file (maximum 10 files, each up to about 60 kB)
java.util.logging.FileHandler.pattern       = ALL
java.util.logging.FileHandler.formatter     = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.pattern       = SOFA-Log-%g.txt
java.util.logging.FileHandler.count         = 10
java.util.logging.FileHandler.limit         = 60000
java.util.logging.FileHandler.append        = true
```

This Logger configuration file writes the logging output to `System.out` and to the files `SOFA-Log-0.txt` to `SOFA-Log-9.txt`.

#### **Output Example**

```
2022-10-19T15:54:29.742 FEIN        SOFA (Simple OAuth 2.0 Framework for Authentication) Version 1.0.0 (2022-10-19) initialization called  
2022-10-19T15:54:29.742 FEIN        SOFA running on OS platform <Windows 8 6.2/amd64>  
2022-10-19T15:54:29.742 FEIN        SOFA running on JVM version <International Business Machines Corporation openj9-0.29.0>  
2022-10-19T15:54:29.742 FEIN        SOFA AES-256 cipher initialized  
2022-10-19T15:54:29.742 FEIN        SOFA object initialized  
2022-10-19T15:54:29.742 FEIN        SOFA authenticate() called  
2022-10-19T15:54:29.742 FEIN        OAuth authorization endpoint <https://login.microsoftonline.com/11111111-2222-3333-4444-555555555555/oauth2/v2.0/token>  
2022-10-19T15:54:29.742 FEIN        OAuth authorization scope <https://outlook.office365.com/.default>  
2022-10-19T15:54:29.742 FEIN        OAuth client ID <66666666-7777-8888-9999-111111111111>  
2022-10-19T15:54:29.742 FEIN        OAuth grant type <client_credentials>  
2022-10-19T15:54:29.742 FEIN        SOFA executeHttpTransaction() called  
2022-10-19T15:54:29.742 FEIN        HTTP connecting to URL <https://login.microsoftonline.com/11111111-2222-3333-4444-555555555555/oauth2/v2.0/token>  
2022-10-19T15:54:29.742 FEIN        HTTP method <POST>  
2022-10-19T15:54:29.757 FEIN        HTTP header sent <Date: Wed, 19 Oct 2022 13:54:29 GMT>  
2022-10-19T15:54:29.757 FEIN        HTTP header sent <User-Agent: SOFA/1.0.0 (Simple OAuth 2.0 Framework for Authentication)>  
2022-10-19T15:54:29.757 FEIN        HTTP header sent <Accept: application/json>  
2022-10-19T15:54:29.757 FEIN        HTTP header sent <Content-Type: application/x-www-form-urlencoded>  
2022-10-19T15:54:29.757 FEIN        HTTP header sent <Content-Length: 188>  
2022-10-19T15:54:29.945 FEIN        HTTP data size sent <188 bytes>  
2022-10-19T15:54:29.945 FEIN        HTTP connection established with cipher <TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <HTTP/1.1 200 OK>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <x-ms-ests-server: 2.1.13943.8 - WEULR1 ProdSlices>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <X-Content-Type-Options: nosniff>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Pragma: no-cache>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <P3P: CP="DSP CUR OTPi IND OTRi ONL FIN">  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Date: Wed, 19 Oct 2022 13:54:29 GMT>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Strict-Transport-Security: max-age=31536000; includeSubDomains>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Cache-Control: no-store, no-cache>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Set-Cookie: stsservicecookie=estsfd; path=/; secure; samesite=none; httponly>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Expires: -1>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Content-Length: 1595>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <X-XSS-Protection: 0>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <x-ms-request-id: 11111111-4444-5555-6666-777777777777>  
2022-10-19T15:54:30.070 FEIN        HTTP header received <Content-Type: application/json; charset=utf-8>  
2022-10-19T15:54:30.070 FEIN        HTTP response code <200>  
2022-10-19T15:54:30.070 FEIN        HTTP data size received <1595 bytes>  
2022-10-19T15:54:30.070 FEIN        SOFA executeHttpTransaction() elapsed time <328 ms>  
2022-10-19T15:54:30.070 FEIN        SOFA parseJsonResponse() called  
2022-10-19T15:54:30.085 FEIN        OAuth access token size received <1520> bytes  
2022-10-19T15:54:30.085 FEIN        OAuth returned token type <Bearer>  
2022-10-19T15:54:30.085 FEIN        OAuth returned access token expiration <3599> seconds  
2022-10-19T15:54:30.085 FEIN        OAuth access token expiration date <Wed Oct 19 16:53:29 CEST 2022>  
2022-10-19T15:54:30.085 FEIN        SOFA getAccessToken() called  
2022-10-19T15:54:30.085 FEIN        SOFA Refresh token not necessary - Returning saved OAuth 2.0 access token 
```


# FAQ

Frequently Asked Questions

#### **Q: How should I use this class?**

* You need to first instantiate a SOFA object with the authorization server and the authorization scope.
* The application then calls the appropriate `authenticateWithXxx()` method based on the desired OAuth 2.0 authentication method (grant type).
* From then on, the application can get a valid access token anytime thru `getAccessToken()` or a ready-to-use HTTP authorization header with `getHttpAuthorizationHeader()`. If the access token has expired in the meantime, SOFA will transparently call the authorization server again for a refreshed or a new token based on the used grant type.
* The HTTP authorization header with the access token must then be added to each HTTP request sent to the server holding the protected resource.

#### **Q: Does SOFA need any additional library or jar files?**

* Only one additional library (`org.json.JSONObject`) is used to parse the returned JSON data from the authorization server. The required class is included in the distribution package.

#### **Q: Is SOFA affected by the Apache Log4j vulnerability?**

* No, SOFA uses the standard Java Logger class which was not affected by this vulnerability.&#x20;

#### Q: How can I get support?

* Support is provided on best-effort basis. You may contact the author thru email at <andy.brunner@k43.ch>. Please describe your problem as detailed as possible and include the [debugging](/quick-start/logging-debugging) log whenever possible. Note that the log does not include any confidential data.


# Microsoft Azure Registration

How to register OAuth 2.0 for Microsoft Azure

### Application Registration

* Open [Azure Portal](https://portal.azure.com) website
* Select "App Services"
* Select "App registrations"
* Select "+ New registration"
* Enter any name, e.g. "SOFA Application"
* Add the API permissions required by your application&#x20;

### Create Client Secret

* Select "Add a certificate or secret"
* Select "+ New client secret"
* Enter any desription e.g. "SOFA Client", set the expiration and press "ADD"

### SOFA Parameters

Set the calling arguments in the SOFA class as follows:

<table><thead><tr><th width="214">Microsoft AD</th><th>SOFA Argument Example (MS 365 Outlook)</th></tr></thead><tbody><tr><td>Authorization Server<br></td><td>https://login.microsoftonline.com/11111111-2222-3333-4444-55555555555/oauth2/v2.0/token</td></tr><tr><td>Authorization Scope</td><td>https://outlook.office365.com/.default</td></tr><tr><td>Client ID/Secret</td><td>66666666-7777-888-9999-11111111111</td></tr><tr><td>Client Secret/Value</td><td>puG8Qak340dhfnskfrieuhnfe3dr.456saa.O</td></tr></tbody></table>


# Google Cloud Registration

How to register OAuth 2.0 for Google Cloud

{% hint style="danger" %}
This page is under construction and not yet finalized or verified. Please let me know if you have a running example.
{% endhint %}

### Application (Project) Registration

* Open [Google Cloud Platform](https://console.developers.google.com) website
* Click on "Select a project" and secect "NEW PROJECT"
* Enter any name, e.g. "SOFA Project" and select "CREATE"

### Create Client Secret

* Select "APIs & Services" > "Credentials"
* Select "+ CREATE CREDENTIALS" > "OAuth client ID"

{% hint style="info" %}
You may be prompted to configure the consent screen before continuing.
{% endhint %}


# Integrate With Non-Java Code

How to integrate SOFA with other languages

### LotusScript (HCL Notes/Domino)

LotusScript to Java (LS2J) allows you to call Java code directly from your HCL Notes/Domino application code.

#### Step 1: Download SOFA

* [Download *SOFA*](/quick-start/downloads) and rename the file *SOFA.jar* to *SOFA.zip*

#### Step 2: Import the SOFA classes into HCL Domino Designer:

* Expand *Code > Script Libraries*
* *New Script Library*: Create a new library (e.g. "OAuth-SOFA-Java") of Type *Java*
* *Import > Archive* and select the directory with the *SOFA.zip* file from the previous step
* *Save* the script library&#x20;

{% hint style="info" %}
These Java class files will be stored in the background. There will be no visible information in HCL Domino Designer.
{% endhint %}

#### Step 3: Use the code

Add the following two statements in your LotusScript code:

{% code lineNumbers="true" %}

```visual-basic
'-- LotusScript to Java Connector
UseLSX "*javacon"

'-- SOFA Java Classes
Use "OAuth-SOFA-Java"        '-- Script library from step 2
```

{% endcode %}

#### Sample Database

{% file src="/files/I1bUMe7B3ZTcnQPAX6rW" %}


