Intro
Terminology
OAuth 2
JWT Family
HTTP Signatures
SmartThings Uses
Scaling Auth
Jeff Beck
Software at SmartThings
A platform for IoT, connect and automate all your devices.
Multiple Mobile Clients
Many Connected Devices
Open API
>150 μ-services
Java, Groovy, Kotlin, Scala, Rust, JavaScript, Swift
Grails, Ratpack, SpringBoot, Micronaut, Dropwizard, …
Principal — The entity acting with the credential.
Authentication Auth(n) — proving something is the requested principal
Authorization Auth(z) — granting what a principal can do
Two major uses:
Your application has it’s own Authorization Server
Your Application is integrating with a 3rd party
This is where you are defining all the clients that integrate with your system. Personally called "OAuth In" as these are things calling to your system to operate on it.
This is where you are getting a single client from a 3rd party that your whole application uses. Personally called "OAuth Out" as it is dealing with authorization that is done externally.
Clients
Grants
Scopes
Tokens
The application that is doing the call for authorization.
Client ID
Client Secret
Set of Grants
Set of Scopes
Name — Human readable name of a client.
Token Expiration — How long should an access token be valid
Refresh Expiration — How long should a refresh be valid
Redirect URI — Used for Authorization Code, what urls are valid for this client.
OAuth grants describe HOW a token is given out. For a given OAuth Client they have a set of acceptable grants available.
Authorization Code
Client Credentials
Implicit
Refresh
Device OAuth
The traditional OAuth Grant flow, the user is presented with a authorize page after clicking authorize we redirect back to the 3rd party including an auth code. The 3rd party posts the code and gets the token set back.
This is a grant that doesn’t have a principal, it just uses the client itself. The client id and secret are used to directly get a token. This is a non principaled version of password grant.
This grant is used internally to the system. It means authentication and authorization have happened outside of oauth.
Used to keep an authorization active.
You send in a refresh token to get a new token and refresh token.
Really useful for devices with screens but not great input.
What can the client actually do. Always limit integrations to the least needed access (PoLP)
user — Read Write Access to user profile
read:user — Just read access to user profile
user:email — Read users email address
delete_repo — Delete a Repo
Designed to allow PoLP
Fine Grained Scopes limiting access to areas of the platform
Scopes within an area like devices break down more what can be done.
Permission – What you can do to the entity
R – Read about the entity
W – Write change things about the entity
X – Execute commands
Entity-Type – What is this? Device, Location, Scene, …
Entity-Id – Which Thing?
Location with 2 Devices
Device 123: Smart lock
Device 555: Temperature sensor
Can Read the state of all details of the devices 123 and 555.
Can’t execute commands
Can’t write device details like changing the name of the device
Can Read the state of all details of the devices 123, 555.
Can execute commands for 123
Can’t write device details like changing the name of the device
Can’t execute commands on 555
Access
Refresh
Shorter lived
Used to access the APIs themselves
Sent many times
Should be stored securely
Allows getting new access tokens
Sent infrequently
Long lived
JWS - JSON Web Signature
JWT - JSON Web Token
JWE - JSON Web Encryption
A way of signing, allows us to trust the data being exchanged.
Allows keeping data client-side such as user or id without worry of tampering
Enables JWT
An open way of representing security claims. Built off of JWS.
They can be used as an access token; providing a self encoded token.
Reduce datastore calls for the credentials.
eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJhdXRoLm15ZG9tYWluLmNvbSIsImF1ZCI6IkExQjJDM0Q0RTUuY29tLm15ZG9tYWluLm15c2VydmljZSIsInN1YiI6ImphY2suc3BhcnJvd0BleGFtcGxlLmNvbSIsImluZm8iOiJIZWxsbyBXb3JsZCEiLCJsaXN0IjpbMSwyLDNdLCJleHAiOjE1NTg4ODY5NDMsImlhdCI6MTU1ODg4MzM0M30.Yx9fJClRiHEA-K3GM6lMYM5yUfOms83OD7mQReVfUlg
{
header: { alg: 'HS256' },
payload:
{ iss: 'auth.mydomain.com',
aud: 'A1B2C3D4E5.com.mydomain.myservice',
sub: 'jack.sparrow@example.com',
info: 'Hello World!',
list: [ 1, 2, 3 ],
exp: 1558886943,
iat: 1558883343 }
}
Key to Verify Signature
$2b$10$ZK4oBaeh1FxM/K2cyI8/ceKqswYpVQwhE1yJz8zi7UUFwvKWB58Vu$2b$10$2IORPEmsyJi5d/5kg8GBGuGv28L69QOVM
Payload is in plaintext. JWE Can Address
Hard to Revoke
Can get very long for headers
Great way to reduce hops
A standard way of encrypting the payload of a JWT.
eyJhbGciOiJQQkVTMi1IUzM4NCtBMTkyS1ciLCJlbmMiOiJBMTkyR0NNIiwicDJjIjoxMDAwLCJwMnMiOiJVRUpGVXpJdFNGTXpPRFFyUVRFNU1rdFhBSU5kR21rY0g3emEifQ.8Q4fsEKZv5LXadmcQFiyzuq0R2nvHKQoadr9BIwQ4HM.qkFyEAVf2Rh8KRf7.4xtybi-H355cBzDRyc-mxqqlwwf3e72q34X9y6A-Kp2Yi1NngbNYYVjvuoL9oMFrdPQBghIYQR4H5qShxC8heGGlQBn53OJEH6BYx2yjh5qo19BXU5_J-uQ6SmCeVkLIOFS9HaEhIJNkkywezhld8-K2vhAsUQmAHK8Yga8lJP8HyG3yAa-XQ0bCTuFWsI6Er7M6qNRlh5LJIKcJFMnpaU6Erfy8evpm7mHGC04.FkwYMNPBZRSyizC3GcVvHA
{
header:
{ alg: 'PBES2-HS384+A192KW',
enc: 'A192GCM',
p2c: 1000,
p2s: 'UEJFUzItSFMzODQrQTE5MktXAINdGmkcH7za' },
payload:
{ iss: 'auth.mydomain.com',
aud: 'A1B2C3D4E5.com.mydomain.myservice',
sub: 'jack.sparrow@example.com',
info: 'Hello World!',
list: [ 1, 2, 3 ],
exp: 1558886943,
iat: 1558883343 }
}
A way to sign the content of a request, protects from tampering and replays. Also easy validate without many external calls.
AWS API — But not exactly
Slack Calls — But custom
Creates a digest of things like the date and host headers that are signed. The public keys can be provided at a known URL and highly cached.
Only Sign Parts of the request that aren’t transformed
Exclude rate limit headers, forwarded for etc
Expose a SET of Public Keys to allow rolling them
Receiver of the call decides to check the signature
API Integrations
Mobile Client
SmartApps
Automation Integrations
Service Providers
Outbound Calls to SmartApps
Used to allow 3rd party to very we are who we say
Integrations with other clouds
Voice Agents - Alexa/Google Home
Cloud devices - Arlo
Web Sessions
Token Exchange at edges
What makes auth at scale hard?
Centralized by Default
High Cardinality for Everything
Can’t break legacy
Overtime you may have multiple auth systems, different backends.
If you are supporting multiple token types such as JWT and opaque. You will want to handle them differently.
1323.443.23
— Looks like JWT because of the .
234-23-22
— Looks like an opaque token with -
We can support many data stores with prefixes allowing quick routing.
We can extend to allow client side routing
If you expect all μ-services to check a forwarded token you pay the token check time every hop.
The high cardinality of auth systems tend to make operating them very challenging at scale.
Ability to very early on in process to block bad actors
Can load lists in bloom filters
Add names to clients
Quick Methods to Allow/Deny access based on easy identifiers
Scope Aliasing
Logging Prefixes of Tokens
Small blips can easily cause big issues.
If you are cascading calls make sure to agree on what an auth failure means. Instead of auth failure resulting in a 4XX default to a known 5XX.
A datastore failed so we started returning a 500 from the auth server.
App Servers treated an auth 500 as a 401
Mobile clients got 401s and triggered refreshing tokens
Mobile clients put more pressure on the already failing datastore
Go back to 1
401 — Means get a new token
403 — Means don’t do that again
5XX — Try again but coordinate jitter and back off