Skip to main content
Server to Server JWT from FileMaker.
Server to Server JWT from FileMaker

If you’ve ever felt trapped trying to connect FileMaker to Google APIs securely, you’re not alone. The world of OAuth 2.0, service accounts, and JWT tokens can feel like stepping into a cryptographic maze—but it doesn’t have to be.

The truth is, generating a valid JWT (JSON Web Token) from FileMaker is one of the most powerful yet underutilized skills in the FileMaker ecosystem. It’s the bridge between your FileMaker database and Google’s world-class services—from Cloud Storage to BigQuery, from Sheets to Drive—all while maintaining enterprise-grade security. And yet, most developers either avoid it entirely or cobble together solutions that feel fragile and incomplete.

What if I told you that with just a few custom functions, you could generate production-ready JWT tokens directly from FileMaker? No external servers. No third-party middleware. Just your data, your rules, and bulletproof authentication. This guide walks you through the complete anatomy of a JWT, shows you exactly how to construct one in FileMaker, and gives you battle-tested custom functions you can use today—whether you’re building a data integration layer, automating backups to Google Cloud, or orchestrating complex multi-system workflows.

JWT Anatomy #

Using OAuth 2.0 for Server to Server Applications (Service Accounts)

General Flow #

Creating the JWT token…

JWT Composition #

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}
JWT header #

signing algorithm and the format of the assertion. In this case: RSA SHA-256 and JWT token format

{"alg":"RS256","typ":"JWT"}
JWT claim set #

params are:

NameDescription
issThe email address of the service account
scopeA space-delimited list of the permissions that the application requests
audA descriptor of the intended target of the assertion. When making an access token request this value is always https://oauth2.googleapis.com/token
expThe expiration time of the assertion, specified as seconds since 00:00:00 UTC
iatThe 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
}
additional claims #

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.

NameDescription
subThe 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
}
encoding claim set #

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.

Script #

Custom functions #

GenerateJWT( ) #

Usage #

GenerateJWT( iss; scope; aud; pk )

Sample #
GenerateJWT(
	"YOUR_SERVICE_ACCOUNT_EMAIL";
	"https://www.googleapis.com/auth/devstorage.read_only";
	"https://oauth2.googleapis.com/token";
	"YOUR_PRIVATE_KEY"
)
Dependendencies #
(CF) UnixTime()
(CF) Base64urlEncode(str)
ClaimSet parameters #
  • 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

)

UnixTime( ) #

Just returns the seconds since 00:00:00 UTC

Floor( GetAsNumber ( Get ( CurrentTimeUTCMilliseconds ) ) / 1000 ) - GetAsNumber ( Timestamp ( "01/01/1970" ; "00:00:00" ) )

Base64urlEncode( ) #

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";""];["=";""] )
 )
 

Get the Token #

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.