Storyblok Raises $80M Series C - Read News

Skip to main content

OAuth 2.0 Authorization Flow

INFO:

On May 13th, 2024, Storyblok started gradually rolling out a new design for its Visual Editor. Therefore, the Visual Editor product screenshots depicted in this resource may not match what you encounter in the Storyblok App. For more information and a detailed reference, please consult this FAQ on the new Visual Editor design.

OAuth 2.0 is a protocol that allows applications to grant limited access to its resources to other applications without having to expose any credentials. Storyblok provides an authentication service that allows plugins to obtain a Content Management API access token, using the Authorization Code Grant method.

Getting Started

To create a new plugin, we highly recommend that you follow our getting started guide and use one of the starter projects. The starter projects use the @storyblok/app-extension-auth library, which handles the somewhat complex OAuth 2.0 authentication flow that is described in this article.

Opening an App for the First Time

After installing a plugin to a space, and when opening that plugin for the very first time, the Storyblok frontend application redirects to a page where the user is asked to approve (or disapprove) the app:

This redirect is necessary because of iframe security restrictions. Once the user has approved the application, Storyblok redirects the user agent to the redirect_uri that is specified in the plugin's settings. The redirect will happen in the top window–that is, outside the iframe. Thus, the user will end up at a URL that shows the plugin. But the user expected to see the Storyblok application with the plugin embedded within an iframe. Therefore, a plugin should once again redirect the user agent back to Storyblok, using a URL that depends on the type of plugin:

  • Sidebar Application: https://app.storyblok.com/oauth/app_redirect
  • Tool Plugin: https://app.storyblok.com/oauth/tool_redirect

For example, when the component mounts, run the following code as a side effect:

        
      if (typeof window !== 'undefined' && window.top === window.self) {
 
 window.location.assign('https://app.storyblok.com/oauth/app_redirect')
}
    

You can find examples in each starter.

OAuth 2.0 Authorization Flow

Storyblok supports the Authorization Code Grant method for authorizing plugins. The first step is to find out what the client_id and client_secret parameters are defined as for your app.

Get credentials

When you create a Storyblok plugin, a pair of client_id and a client_secret are generated.

The client_secret is confidential–keep it to yourself.

Authorization Request

With your credentials already configured, the next step is to make a request to ask for permission fields in Storyblok. Below is a description of the following URL:

https://app.storyblok.com/oauth/authorize?client_id=<YOUR_CLIENT_ID>&response_type=code&redirect_uri=<YOUR_REDIRECT_URI>&scope=read_content write_content&state=<SOME_UUID>&code_challenge=<SHA_CODE>&code_challenge_method=S256
  • client_id: the client id.
  • redirect_uri: the URL for redirect with the grant code.
  • scope: a list of permissions to ask separated by space.
  • state: A string value used by the client to maintain state between the request and callback. The authorization server includes this value when redirecting the user-agent back to the client. The parameter should be used for preventing cross-site request forgery.
  • code_challenge: a string relates to the code challenge method.
  • code_challenge_method: code challenge method, can be plain or SHA256 .

The primary reason for using the state parameter is to mitigate CSRF attacks. Before redirecting a request to the Identity Provider (IdP), have the app generate a random string and store the string locally in a cookie.

The code_challenge and code_challenge_method belongs to the PKCE extension. You can read more about PKCE in the following link.

When you make this request for the first time, Storyblok will display the folling:

After it has been approved, Storyblok will immediately redirect back to the redirect_uri.

Authorization Response

When the user approves your permissions, the Storyblok system will redirect the page for the following URL:

{redirect_uri}?code={code}&state={state}&space_id={space_id}
  • redirect_url: the redirect URL that you configured in your application
  • code: a code generated by Storyblok for your app to request the access and refresh tokens
  • state: The exact value received from the client.
  • space_id: the space the user allowed your application to access

Retrieve the returned state value and compare it with the one you stored in a cookie earlier. If the values match, then approve the authentication response, else deny it.

Access Token Request

In the redirect_uri request handler, figure out from which region the space is from. If the spaceId is less than a million (1 000 000), then it's an eu space; otherwise, it is a us space.

With this information, make a POST request to Storyblok, to obtain the access token. The URL depends on the region:

  • eu: https://app.storyblok.com/oauth/token
  • us: https://app.storyblok.com/v1_us/token

The body request must be form url encoded with the following parameters:

  • grant_type: must be a string with 'authorization_code'
  • code: the grant code that comes from redirect
  • client_id: the client id
  • client_secret: the client secret
  • redirect_uri: the URL that will be used to receive the access and refresh tokens

The result of this request is a JSON object with the following structure:

{
  "access_token": "<ACCESS_TOKEN>",
  "refresh_token": "<REFRESH_TOKEN>",
  "token_type": "bearer",
  "expires_in": 899
}

Refreshing the access token

To refresh your token, you must make a form url encode request to the access token, but with other parameters described below:

  • grant_type: must be a string with 'refresh_token'
  • refresh_token: the refresh token
  • client_id: the client id
  • client_secret: the client secret
  • redirect_uri: the URL that will be used to receive the access and refresh tokens

The result of this request is the same of the get access token request, but without the refresh token field.

Getting User Info

To get the currently logged-in user and the space role you can send an authenticated GET request to the user_info endpoint:

  • eu: https://api.storyblok.com/oauth/user_info
  • us: https://api-us.storyblok.com/oauth/user_info

For example:

$ curl 'https://api.storyblok.com/oauth/user_info' -H 'authorization: Bearer YOURTOKEN'

This will return a user object and a array of space roles:

{
  "user": {
    "friendly_name": "My name",
    "id": 20
  },
  "roles": [
    {
      "name": "admin"
    }
  ]
}

Note that the access token belongs to the application–it must not be exposed to the user. The scope of the access token is the same regardless of the user that is using the app.

Making Authenticated Requests

To authenticate requests to Storyblok API, you must add an 'Authorization' header with the 'Bearer <ACCESS_TOKEN>'. See the Management API docs. Note that not all endpoints in the Management API are available for plugins. Please read the Management API Reference to find out which endpoints are accessible with the OAuth token.

Further Reading

To read more about the OAuth2 protocol and understand more about token authentication, check out the following resources: