What is a token?
Fleet Engine requires the use of JSON Web Tokens(JWTs) for API method calls from low-trust environments: smartphones and browsers.
A JWT originates on your server, is signed, encrypted, and passed to the client for subsequent server interactions until it expires or is no longer valid.
Key details
- Use Application Default Credentials to authenticate and authorize against Fleet Engine.
- Use an appropriate service account to sign JWTs. See Fleet Engine serviceaccount roles in Fleet Engine Basics.
For more information about JSON Web Tokens, see JSON Web Tokens in Fleet Engine Essentials.
How clients get tokens?
Once a driver or consumer logs in to your app using the appropriate authentication credentials, any updates issued from that device must use appropriate authorization tokens, which communicates to Fleet Engine the permissions for the app.
As the developer, your client implementation should provide the ability to do the following:
- Fetch a JSON Web Token from your server.
- Reuse the token until it expires to minimize token refreshes.
- Refresh the token when it expires.
The GMTDAuthorization
protocol fetches JSON Web tokens at location update time
based on the GMTD AuthorizationContext
object. The SDK
must package the tokens with the update information to send to Fleet Engine.
Make sure that your server-side implementation can issue tokens before
initializing the SDK.
For details of the tokens expected by Fleet Engine, see Issue JSON Web Tokens for Fleet Engine.
The providerID is the same as the Project IDof your Google Cloud Project. For information on setting up the Google Cloud Project, see Create your Fleet Engine project .
Example of an authentication token fetcher
The following example implements an authorization token provider:
Swift
/*
* SampleAccessTokenProvider.swift
*/
import
GoogleRidesharingConsumer
private
let
providerURL
=
"INSERT_YOUR_TOKEN_PROVIDER_URL"
class
SampleAccessTokenProvider
:
NSObject
,
GMTCAuthorization
{
private
struct
AuthToken
{
// The cached trip token.
let
token
:
String
// Keep track of when the token expires for caching.
let
expiration
:
TimeInterval
// Keep track of the trip ID the cached token is for.
let
tripID
:
String
}
enum
AccessTokenError
:
Error
{
case
missingAuthorizationContext
case
missingData
}
private
var
authToken
:
AuthToken
?
func
fetchToken
(
with
authorizationContext
:
GMTCAuthorizationContext
?,
completion
:
@
escaping
GMTCAuthTokenFetchCompletionHandler
)
{
// Get the trip ID from the authorizationContext. This is set by the Consumer SDK.
guard
let
authorizationContext
=
authorizationContext
else
{
completion
(
nil
,
AccessTokenError
.
missingAuthorizationContext
)
return
}
let
tripID
=
authorizationContext
.
tripID
// If appropriate, use the cached token.
if
let
authToken
=
authToken
,
authToken
.
expiration
>
Date
.
now
.
timeIntervalSince1970
&&
authToken
.
tripID
==
tripID
{
completion
(
authToken
.
token
,
nil
)
return
}
// Otherwise, try to fetch a new token from your server.
let
request
=
URLRequest
(
url
:
URL
(
string
:
providerURL
))
let
task
=
URLSession
.
shared
.
dataTask
(
with
:
request
)
{
[
weak
self
]
data
,
_
,
error
in
guard
let
strongSelf
=
self
else
{
return
}
guard
error
==
nil
else
{
completion
(
nil
,
error
)
return
}
// Replace the following key values with the appropriate keys based on your
// server's expected response.
let
tripTokenKey
=
"TRIP_TOKEN_KEY"
let
tokenExpirationKey
=
"TOKEN_EXPIRATION"
guard
let
data
=
data
,
let
fetchData
=
try
?
JSONSerialization
.
jsonObject
(
with
:
data
)
as
?
[
String
:
Any
],
let
token
=
fetchData
[
tripTokenKey
]
as
?
String
,
let
expiration
=
fetchData
[
tokenExpirationKey
]
as
?
Double
else
{
completion
(
nil
,
AccessTokenError
.
missingData
)
return
}
strongSelf
.
authToken
=
AuthToken
(
token
:
token
,
expiration
:
expiration
,
tripID
:
tripID
)
completion
(
token
,
nil
)
}
task
.
resume
()
}
}
Objective-C
/*
* SampleAccessTokenProvider.h
*/
#import <Foundation/Foundation.h>
#import <GoogleRidesharingConsumer/GoogleRidesharingConsumer.h>
NS_ASSUME_NONNULL_BEGIN
@interface
SampleAccessTokenProvider
: NSObject
< GMTCAuthorization
> @end
NS_ASSUME_NONNULL_END
/*
* SampleAccessTokenProvider.m
*/
#import "SampleAccessTokenProvider.h"
#import "GoogleRidesharingConsumer/GoogleRidesharingConsumer.h"
static
NSString
*
const
PROVIDER_URL
=
@"INSERT_YOUR_TOKEN_PROVIDER_URL"
;
// SampleAccessTokenProvider.m
@implementation
SampleAccessTokenProvider
{
// The cached token with claims to the current trip.
NSString
*
_cachedTripToken
;
// Keep track of the Trip ID the cached token is for.
NSString
*
_lastKnownTripID
;
// Keep track of when tokens expire for caching.
NSTimeInterval
_tokenExpiration
;
}
-
(
void
)
fetchTokenWithContext:
(
nullable
GMTCAuthorizationContext
*
)
authorizationContext
completion
:(
nonnull
GMTCAuthTokenFetchCompletionHandler
)
completion
{
// Get the trip ID from the authorizationContext. This is set by the Consumer SDK.
NSString
*
tripID
=
authorizationContext
.
tripID
;
// Clear cached trip token if trip ID has changed.
if
(
!
[
_lastKnownTripID
isEqual
:
tripID
])
{
_tokenExpiration
=
0.0
;
_cachedTripToken
=
nil
;
}
_lastKnownTripID
=
tripID
;
// Clear cached tripToken if it has expired.
if
([[
NSDate
date
]
timeIntervalSince1970
]
>
_tokenExpiration
)
{
_cachedTripToken
=
nil
;
}
// If appropriate, use the cached token.
if
(
_cachedTripToken
)
{
completion
(
_cachedTripToken
,
nil
);
return
;
}
// Otherwise, try to fetch a new token from your server.
NSURL
*
requestURL
=
[
NSURL
URLWithString
:
PROVIDER_URL
];
NSMutableURLRequest
*
request
=
[[
NSMutableURLRequest
alloc
]
initWithURL
:
requestURL
];
request
.
HTTPMethod
=
@"GET"
;
// Replace the following key values with the appropriate keys based on your
// server's expected response.
NSString
*
tripTokenKey
=
@"TRIP_TOKEN_KEY"
;
NSString
*
tokenExpirationKey
=
@"TOKEN_EXPIRATION"
;
__weak
typeof
(
self
)
weakSelf
=
self
;
void
(
^
handler
)(
NSData
*
_Nullable
data
,
NSURLResponse
*
_Nullable
response
,
NSError
*
_Nullable
error
)
=
^
(
NSData
*
_Nullable
data
,
NSURLResponse
*
_Nullable
response
,
NSError
*
_Nullable
error
)
{
typeof
(
self
)
strongSelf
=
weakSelf
;
if
(
error
)
{
completion
(
nil
,
error
);
return
;
}
NSError
*
JSONError
;
NSMutableDictionary
*
JSONResponse
=
[
NSJSONSerialization
JSONObjectWithData
:
data
options
:
kNilOptions
error
:
& JSONError
];
if
(
JSONError
)
{
completion
(
nil
,
JSONError
);
return
;
}
else
{
// Sample code only. No validation logic.
id
expirationData
=
JSONResponse
[
tokenExpirationKey
];
if
([
expirationData
isKindOfClass
:
[
NSNumber
class
]])
{
NSTimeInterval
expirationTime
=
((
NSNumber
*
)
expirationData
).
doubleValue
;
strongSelf
-
> _tokenExpiration
=
[[
NSDate
date
]
timeIntervalSince1970
]
+
expirationTime
;
}
strongSelf
-
> _cachedTripToken
=
JSONResponse
[
tripTokenKey
];
completion
(
JSONResponse
[
tripTokenKey
],
nil
);
}
};
NSURLSessionConfiguration
*
config
=
[
NSURLSessionConfiguration
defaultSessionConfiguration
];
NSURLSession
*
mainQueueURLSession
=
[
NSURLSession
sessionWithConfiguration
:
config
delegate
:
nil
delegateQueue
:[
NSOperationQueue
mainQueue
]];
NSURLSessionDataTask
*
task
=
[
mainQueueURLSession
dataTaskWithRequest
:
request
completionHandler
:
handler
];
[
task
resume
];
}
@end