🔐

OAuth

Overview

The purpose of having OAuth details on an SSS feed is to allow the feed to contain exclusive content.
The technical problem OAuth helps us solve is that creators upload their content to a Hosting Provider (eg: Taddy Ink), but consumers use a different app (eg: Inkverse) to view content. Therefore, if a creator wants to have exclusive content that is only available to their Patreon backers, how do Taddy and Inkverse work together to verify that only paid users can access exclusive content? We use an OAuth workflow to do so.
 
Taddy Ink (Hosting Provider) and Inkverse (Client App) are used as examples but can be replaced with any alternative conforming to the SSS open specification.
Taddy Ink (Hosting Provider) and Inkverse (Client App) are used as examples but can be replaced with any alternative conforming to the SSS open specification.
Our OAuth workflow can be summarized as OAuth with one additional step. That one additional step is to make one more request to get a content token. The content token gives you access to content for a specific comic.
 
💡
Follow along with this example:
Our Test comic, Larry’s Lullaby, is free to read. However, to access the latest 3 episodes of the comic you have to be a Free Patreon backer of Taddy Ink (Free tier). Follow the steps below to be able to view the latest 3 episodes:
 
  1. Sign up as a developer. Then, go to the Taddy OAuth section to create a client application (including adding your application name, logo, and callback URL).
  1. Open a new tab, in your browser and go to patreon.com. Log into your Patreon account. Next, go to Taddy Ink’s Patreon account and click ‘Join for free’ to become a free Patreon backer. (This will give you exclusive access to last 3 episodes of Larry’s Lullaby)
  1. Use the authorizeUrl (see Taddy’s OAuth details below) and read the authorizeUrl documentation below to format the required URL parameters appropriately (Step 1 of OAuth).
  1. Make a POST request to the tokenUrl endpoint. Use the authorization code you got in Step 1 along with your client secret to get an access and refresh token (Step 2 of OAuth)
  1. Make a POST request to the newContentTokenUrl endpoint. Use the access token you got from Step 2 and the comic series uuid to get a content token for exclusive content from this series.
  1. Now that you have a content token, you can append that content token to view any of the images in exclusive episodes. Append using the url parameter: ?token=contentToken. Paid episodes and will have scopesForExclusiveContent:["patreon] property.
 
oauth: { signupUrl: 'https://taddy.org/developers/signup', authorizeUrl: 'https://taddy.org/fans/authorize', tokenUrl: 'https://taddy.org/auth/oauth2/token', newAccessTokenUrl: 'https://taddy.org/auth/oauth2/new_access_token', newRefreshTokenUrl: 'https://taddy.org/auth/oauth2/new_refresh_token', newContentTokenUrl: 'https://taddy.org/auth/oauth2/new_content_token', instructionsUrl: 'https://taddy.org/developers/instructions' },
Taddy’s OAuth details. It can be found here from Larry’s Lullaby comic feed.
 
notion image
 
Important notes for the Example above:
  • Larry Lullaby’s creator uses Taddy Ink to host their comic. The creator is trusting Taddy Ink to verify that any user who gets access to their exclusive episodes has verified themselves as a Patreon backer.
  • Your app needs to get a token to access exclusive content. To do so, the fan must verify with ‘Login with Patreon.’ on Taddy Ink’s website.
  • Your app doesn't need to implement Patreon OAuth, that is done by Taddy Ink.
  • The exchange and access tokens your app gets back from Taddy Ink are tokens for Taddy Ink, not Patreon. In the future, we may implement more payment platforms like Patreon.
  • Once you have a content token, you can view exclusive episodes by appending it to any image URLs that require a token to access them.

OAuth Properties

Endpoints needed for the OAuth workflow
Property
Type
Description
signupUrl
String
The url to sign up for a client_id and client_secret
authorizeUrl
String
The 1st step in OAuth. The url to get an authorization code.
tokenUrl
String
The 2nd step in OAuth. The url to exchange an authorization code for an access token and a refresh token.
newAccessTokenUrl
String
Once you have a refresh token, you can exchange it for a new access token
newRefreshTokenUrl
String
Once you have a refresh token, you can exchange it for a new refresh token
newContentTokenUrl
String
Once you have an access token, you can exchange it for a new content token
instructionsUrl
String
Additional instructions from the Hosting provider.

signupUrl

The URL to sign up and get a client_id and client_secret and register your callback_url. See instructionsUrl if you need more instructions.

authorizeUrl

The 1st step in OAuth. Send the end user to this URL address to verify they have paid for exclusive content.
 
Example of what an authorizeUrl looks like eg) Taddy Ink
Example of what an authorizeUrl looks like eg) Taddy Ink
 
Append these URL parameters to the authorizeUrl:
Property
Type
Description
client_id
String (Required)
Your client_id
client_user_id
String (Required)
The unique id of a user who wants access to premium content.
response_type
String (Required)
Response type is required to be code
series_uuid
String (Optional)
If passed in, the end user will see series-specific information when they visit the authorizeUrl. If series_uuid is not passed in, the end user sees a more generic “Get exclusive access to your favourite creators” page.
access_token
String (Optional)
If you already have the access_token for the end user, pass it in here. If the end user verifies access to another platform, it will append those permissions to the ones you already have and return a new access & refresh token. If you do not pass in an access_token, you will get a new access & refresh token just for the new platform the end user verified.
state
String (Optional)
You can pass in state.
code_challenge
String (Optional)
For PKCE. Recommended for security purposes.
code_challenge_method
String (Optional)
For PKCE. Recommended for security purposes.
You get back the following data (returned as url parameters appended to your callback_url):
Property
Type
Description
code
String
The authorization code. This is a short-term & one-time code required for step 2 of OAuth.
state
String
If you pass in state in the input, it is returned here as output. This can be useful for security purposes.
 
Example:
https://taddy.org/fans/authorize?response_type=code&client_id=1&client_user_id=4825a834-37c4-4ec4-aade-f0950914e95e
 

tokenUrl

POST endpoint. This is the 2nd step in OAuth. With this endpoint, you can convert the one-time authorization code you got from the 1st step for an access and refresh token. (The second step of OAuth is initialized from your server because it uses your client secret which should never be shared with anyone)
 
Provide the following input:
Property
Type
Description
client_id
String (Required)
Your client_id
client_secret
String (Required)
Your client_secret
code
String (Required)
Authorization Code from the 1st Step.
grant_type
String (Required)
Grant type is required to be authorization_code
code_verifier
String (Optional)
For PKCE. Recommended for security purposes.
You get back the following:
Property
Type
Description
accessToken
String
JWT Token. A short term token that can be exchanged for a content token (which is used to unlock paid content)
refreshToken
String
JWT Token. A long lived token that can be exchanged for an access token or another refresh token.
 
Example:
curl -X POST https://taddy.org/auth/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "code=a0b3b001-ab96-4c7e-b215-d9c18e42202c&client_id=1&client_secret=xyz&grant_type=authorization_code"
 

newAccessTokenUrl

POST endpoint. Once you have a refresh token, you can exchange it for a new access token.
 
Provide the following input:
Property
Type
Description
refresh_token
String (Required)
JWT Token.
You get back the following:
Property
Type
Description
token
String
JWT Token.
 
Example:
curl -X POST https://taddy.org/auth/oauth2/new_access_token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "refresh_token=xyz"
 

newRefreshTokenUrl

POST endpoint. Once you have a refresh token, you can exchange it for a new refresh token.
 
Provide the following input:
Property
Type
Description
refresh_token
String (Required)
JWT Token.
You get back the following:
Property
Type
Description
token
String
JWT Token.
 
Example:
curl -X POST https://taddy.org/auth/oauth2/new_refresh_token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "refresh_token=xyz"
 

newContentTokenUrl

POST endpoint. Once you have an access token, you can exchange it for a new content token.
 
Provide the following input:
Property
Type
Description
access_token
String (Required)
JWT Token.
series_uuid
String (Required)
Unique Id for the series
You get back the following:
Property
Type
Description
token
String
JWT Token. Use this token and append it to any
 
Example:
curl -X POST https://taddy.org/auth/oauth2/new_content_token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "access_token=xyz&series_uuid=e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e"
 
Now you have a content token, you can append it to the end of an image via the url parameter ‘token’.
https://az1.taddy.org/96cc49d7-a95d-4266-b408-b57c7d26a62e/88eec86a-b7d5-4f33-ad89-1f91226dd1e1/9d8094e2-df3c-4795-bbda-d0f3e69add75/story.webp?token=123
 

instructions

Detailed instructions from the Hosting provider on how to signup.
 

Advanced

Example of a refresh JWT token:
{ "aud": "12", // client_id "sub": "789-xyz-123-abc", // client_user_id (user's uuid or id) "iss": "e9957105-80e4-46e3-8e82-20472b9d7512", // uuid of the hosting provider "iss_token_type": "refresh", // token type from the hosting provider "scope": "patreon_123 patreon_456", // verified payment options (separated by spaces) "iat": 1703955098, // issued at time "exp": 1719507098 // expires at time }
 
Example of a content JWT token:
{ "aud": "12", // client_id "sub": "789-xyz-123-abc", // client_user_id (user's uuid or id) "iss": "e9957105-80e4-46e3-8e82-20472b9d7512", // uuid of the hosting provider "iss_token_type": "content", // token type from the hosting provider "scope": "patreon_123 patreon_456", // verified payment options (separated by spaces) "series_uuid": "123-abc-456-def", // which series this content token is for "items": ["456-def-123-abc"] // exclusive episodes you have access to "iat": 1703955098, // issued at time "exp": 1719507098 // expires at time }
 
Access token vs content token:
After you log in and verify your payment option (e.g., Patreon), you get an access token. You can exchange an access token for a content token.
A content token gives you access to paid content from a specific series and lists which items in the series you have access to. You can use the same access token to get content tokens for different series hosted by the same hosting provider.
 
Time limits for each token:
Authorization Code is a short-lived code. Usually ~ 5 minutes.
Refresh Token is a longer-lived token ~ 180 days.
Access Token is a short-lived token ~ 2 hours
Content Token is a short-lived token ~ 2 hours
 
If you would like to edit or contribute to the SSS specification. You can either submit a PR here or by creating a notion account and leaving a comment. Open Source Credit: This website is actually just a notion document. We use Travis's notion + nextjs starter project, you should check it out if you want an easy way to create + edit your docs.