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 shows an implementation of the GMTDAuthorization
protocol.
Swift
import
GoogleRidesharingDriver
private
let
providerURL
=
"INSERT_YOUR_TOKEN_PROVIDER_URL"
class
SampleAccessTokenProvider
:
NSObject
,
GMTDAuthorization
{
private
struct
AuthToken
{
// The cached vehicle token.
let
token
:
String
// Keep track of when the token expires for caching.
let
expiration
:
TimeInterval
// Keep track of the vehicle ID the cached token is for.
let
vehicleID
:
String
}
enum
AccessTokenError
:
Error
{
case
missingAuthorizationContext
case
missingData
}
private
var
authToken
:
AuthToken
?
func
fetchToken
(
with
authorizationContext
:
GMTDAuthorizationContext
?,
completion
:
@
escaping
GMTDAuthTokenFetchCompletionHandler
)
{
// Get the vehicle ID from the authorizationContext. This is set by the Driver SDK.
guard
let
authorizationContext
=
authorizationContext
else
{
completion
(
nil
,
AccessTokenError
.
missingAuthorizationContext
)
return
}
let
vehicleID
=
authorizationContext
.
vehicleID
// If appropriate, use the cached token.
if
let
authToken
=
authToken
,
authToken
.
expiration
>
Date
.
now
.
timeIntervalSince1970
&&
authToken
.
vehicleID
==
vehicleID
{
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
vehicleTokenKey
=
"VEHICLE_TOKEN_KEY"
let
tokenExpirationKey
=
"TOKEN_EXPIRATION"
guard
let
data
=
data
,
let
fetchData
=
try
?
JSONSerialization
.
jsonObject
(
with
:
data
)
as
?
[
String
:
Any
],
let
token
=
fetchData
[
vehicleTokenKey
]
as
?
String
,
let
expiration
=
fetchData
[
tokenExpirationKey
]
as
?
Double
else
{
completion
(
nil
,
AccessTokenError
.
missingData
)
return
}
strongSelf
.
authToken
=
AuthToken
(
token
:
token
,
expiration
:
expiration
,
vehicleID
:
vehicleID
)
completion
(
token
,
nil
)
}
task
.
resume
()
}
}
Objective-C
#import "SampleAccessTokenProvider.h"
#import <GoogleRidesharingDriver/GoogleRidesharingDriver.h>
// SampleAccessTokenProvider.h
@interface
SampleAccessTokenProvider
: NSObject<GMTDAuthorization>
@end
static
NSString
*
const
PROVIDER_URL
=
@"INSERT_YOUR_TOKEN_PROVIDER_URL"
;
// SampleAccessTokenProvider.m
@implementation
SampleAccessTokenProvider
{
// The cached vehicle token.
NSString
*
_cachedVehicleToken
;
// Keep track of the vehicle ID the cached token is for.
NSString
*
_lastKnownVehicleID
;
// Keep track of when tokens expire for caching.
NSTimeInterval
_tokenExpiration
;
}
-
(
void
)
fetchTokenWithContext:
(
nullable
GMTDAuthorizationContext
*
)
authorizationContext
completion
:(
nonnull
GMTDAuthTokenFetchCompletionHandler
)
completion
{
if
(
!
completion
)
{
NSAssert
(
NO
,
@"%s encountered an unexpected nil completion."
,
__PRETTY_FUNCTION__
);
return
;
}
// Get the vehicle ID from the authorizationContext. This is set by the Driver SDK.
NSString
*
vehicleID
=
authorizationContext
.
vehicleID
;
if
(
!
vehicleID
)
{
NSAssert
(
NO
,
@"Vehicle ID is missing from authorizationContext."
);
return
;
}
// Clear cached vehicle token if vehicle ID has changed.
if
(
!
[
_lastKnownVehicleID
isEqual
:
vehicleID
])
{
_tokenExpiration
=
0.0
;
_cachedVehicleToken
=
nil
;
}
_lastKnownVehicleID
=
vehicleID
;
// Clear cached vehicletoken if it has expired.
if
([[
NSDate
date
]
timeIntervalSince1970
]
>
_tokenExpiration
)
{
_cachedVehicleToken
=
nil
;
}
// If appropriate, use the cached token.
if
(
_cachedVehicleToken
)
{
completion
(
_cachedVehicleToken
,
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
*
vehicleTokenKey
=
@"VEHICLE_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
-
> _cachedVehicleToken
=
JSONResponse
[
vehicleTokenKey
];
completion
(
JSONResponse
[
vehicleTokenKey
],
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