Using OAuth 2.0 for Server to Server Applications (Service Accounts)
A JWT is composed as follows:
{Base64url encoded header}.{Base64url encoded claim set}.{Base64url encoded signature}
The base string for the signature is as follows:
{Base64url encoded header}.{Base64url encoded claim set}
signing algorithm and the format of the assertion. In this case: RSA SHA-256 and JWT token format
{"alg":"RS256","typ":"JWT"}
params are:
Name | Description |
---|---|
iss | The email address of the service account |
scope | A space-delimited list of the permissions that the application requests |
aud | A descriptor of the intended target of the assertion. When making an access token request this value is always https://oauth2.googleapis.com/token |
exp | The expiration time of the assertion, specified as seconds since 00:00:00 UTC |
iat | The time the assertion was issued, specified as seconds since 00:00:00 UTC, January 1, 1970 |
{
"iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"scope": "https://www.googleapis.com/auth/devstorage.read_only",
"aud": "https://oauth2.googleapis.com/token",
"exp": 1328554385,
"iat": 1328550785
}
To obtain an access token that grants an application delegated access to a resource, include the email address of the user in the JWT claim set as the value of the sub field.
Name | Description |
---|---|
sub | The email address of the user for which the application is requesting delegated access |
{
"iss": "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
"sub": "some.user@example.com",
"scope": "https://www.googleapis.com/auth/prediction",
"aud": "https://oauth2.googleapis.com/token",
"exp": 1328554385,
"iat": 1328550785
}
The JWT claim set should be serialized to UTF-8 and Base64url-safe encoded
The input for the signature is the byte array of the following content:
{Base64url encoded header}.{Base64url encoded claim set}
The only signing algorithm supported by the Google OAuth 2.0 Authorization Server is RSA using SHA-256 hashing algorithm. This is expressed as RS256 in the alg field in the JWT header.
Sign the UTF-8 representation of the input using SHA256withRSA (also known as RSASSA-PKCS1-V1_5-SIGN with the SHA-256 hash function) with the private key obtained from the Google API Console. The output will be a byte array.
GenerateJWT( iss; scope; aud; pk )
GenerateJWT(
"YOUR_SERVICE_ACCOUNT_EMAIL";
"https://www.googleapis.com/auth/devstorage.read_only";
"https://oauth2.googleapis.com/token";
"YOUR_PRIVATE_KEY"
)
(CF) UnixTime()
(CF) Base64urlEncode(str)
- iss: The email address of the service account
- scope: A space-delimited list of the permissions that the application requests
- aud: A descriptor of the intended target of the assertion. When making an access token request this value is always https://oauth2.googleapis.com/token
- exp: The expiration time of the assertion, specified as seconds since 00:00:00 UTC
- iat: The time the assertion was issued, specified as seconds since 00:00:00 UTC, January 1, 1970
- sub: The email address of the user for which the application is requesting delegated access (only used for delegated access)
Let(
[
_ISS = iss;
_SCOPE = scope;
_AUD = aud;
_PRIVATE_KEY = pk;
_TOKEN_TTL = 3600;
_UTC_ZERO = UnixTime();
header = JSONSetElement ( "{}";
["alg"; "RS256"; JSONString];
["typ"; "JWT"; JSONString] );
claimSet = JSONSetElement ( "{}";
["iss"; _ISS; JSONString];
["scope"; _SCOPE; JSONString];
["aud"; _AUD; JSONString];
["iat"; _UTC_ZERO ; JSONNumber];
["exp"; _UTC_ZERO + _TOKEN_TTL; JSONNumber] );
signatureData = "" & Base64urlEncode ( header ) & "." & Base64urlEncode ( claimSet ) & "";
signature = CryptGenerateSignature ( signatureData ; "SHA256" ; _PRIVATE_KEY ; "" );
signedJWTData = signatureData & "." & Base64urlEncode (signature )
];
signedJWTData
)
Just returns the seconds since 00:00:00 UTC
Floor( GetAsNumber ( Get ( CurrentTimeUTCMilliseconds ) ) / 1000 ) - GetAsNumber ( Timestamp ( "01/01/1970" ; "00:00:00" ) )
Does a "url safe" Base64 Encoding, accordingly to RFC4648 https://tools.ietf.org/html/rfc4648 Do not use simple Base64 native encodings from FileMaker.
Let (
_e=Base64EncodeRFC(4648 ;data );
Substitute( _e;["+";"-"];["/";"_"];["\r";""];["\n";""];["=";""] )
)
Basicaly pass the JWT body to the authentication server as:
$ASSERTION = GenerateJWT( iss; scope; aud; pk )
$GRANT_TYPE = "urn:ietf:params:oauth:grant-type:jwt-bearer"
Post a CURL to the token_uri: https://oauth2.googleapis.com/token with the cURL options:
CURL -X POST -d "grant_type=$GRANT_TYPE&assertion=$ASSERTION"
The result contains your authorization token, expiration date time or error messages if request fails.
This CFunction is not affected by the SHA algorithm deprecation on FMPro 19.x accordingly to this release notes
This has been checked against FMPro 19.6.3.302 by FEB.03.2023