OAuth 2.0 Authorization Flow
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:
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 beplain
orSHA256
.
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 applicationcode
: a code generated by Storyblok for your app to request the access and refresh tokensstate
: 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 redirectclient_id
: the client idclient_secret
: the client secretredirect_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 tokenclient_id
: the client idclient_secret
: the client secretredirect_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: