You can use OAuth 2.0, with full support of the standard authorization code grant flow with Proof Key for Code Exchange (PKCE) for better security, so that users can authorize access to a third-party service.
With our support for PKCE, the only code_challenge
methods supported are S256
and SHA256
.
In general, when OAuth is used, the key players are the following:
The user owns some resource (for example, their list of contacts) that could be made available to functions.
The provider of some service to access this protected resource (for example, Google's contacts service).
You, the developer, who implements the function to access the service, which might not be the provider.
The capsule, which uses Bixby's OAuth 2.0 client to ask for users' authorization, in order to access their resources at the service provider.
As the developer, you need to register your capsule as a standard OAuth 2.0 client that supports the standard Authorization Code Grant type. The client secrets are kept on Bixby's servers. Store the parameters, such as the client ID and the client secret you obtained from the provider, as developer keys with Bixby.
Different providers can be registered with Bixby. A user authorizes a capsule to access a particular scope of capabilities with the provider. To access OAuth APIs, you must have the developer keys registered with the provider, and store them with Bixby. Once the user authorizes access, the capsule receives an access key that allows access to user content from the provider.
In general, Bixby manages all these keys. You can learn more about how to implement OAuth below.
Bixby does not currently support the OAuth 1.0 protocol. Your capsule must authenticate with OAuth 2.0 providers.
There are multiple things you must do to incorporate OAuth into your capsule.
authorization.bxb
file.You would implement your actions with OAuth by using API calls, as you would any other web service within Bixby. For more information and for an example function, you can read about it in the Calling Web Services -- OAuth topic.
You must use HTTPS for OAuth calls. Unencrypted HTTP endpoints are insecure and are not supported!
Bixby's maximum supported length for OAuth access tokens is 2048 characters.
You can use the various JavaScript OAuth APIs to make OAuth calls between the user and the provider, if your JavaScript function has a valid authorization
section.
Bixby has built-in support for endpoints that require OAuth 2.0 authorization. Use the authorization
key and its subkeys to set the parameters for your capsule's external OAuth provider. You need to consult your OAuth provider's documentation to find its endpoint URIs and the parameters that it supports.
You configure OAuth under the authorization
key in an authorization.bxb
file in your capsule's root directory:
authorization {
user {
oauth2-authorization-code (providerId) {
authorize-endpoint (...)
client-id (...)
client-secret-key (...)
scope (...) // optional
token-endpoint (...)
}
}
global {
oauth2-client-credentials (providerId) {
client-id (...)
client-secret-key (...)
scope (...) // optional
token-endpoint (...)
}
}
}
The client-id
is a public identifier for your application, registered with or assigned by your OAuth provider. The OAuth client secret is not stored in your capsule for security reasons. Instead, client-secret-key
is used to look up the secret, which you enter on the Configuration & Secrets screen in the Bixby Developer Center.
You can specify authorization for only a user
, only global
, or both. To then use an authorization method defined in authorization.bxb
with an endpoint, the endpoint must be annotated with authorization { user }
or authorization { global }
. If the endpoint is not annotated with authorization { something }
, no authorization is used for that endpoint:
action-endpoint (MyAction) {
remote-endpoint (...) {
method (POST)
}
authorization {
user
}
}
If you need to use a custom grant-type
for a user, use the oauth2-custom
key to define the authorization.
For an explanation of the authorization
subkeys, see the authorization
reference. Not all authorization
definitions need to include all keys.
Here's another example, using the Spotify Web API:
authorization {
user {
oauth2-authorization-code (Spotify)
authorize-endpoint (https://accounts.spotify.com/authorize)
client-id (spotify-id)
client-secret-key (spotify-secret)
scope (playlist-read-private playlist-read-collaborative ...)
token-endpoint (https://accounts.spotify.com/api/token)
}
}
As part of the OAuth flow, you are required to register a redirect URI (redirect_uri
) with the service provider. Normally, this is set in the service provider's dashboard. Refer to your provider's documentation for more information.
Register Bixby's redirect URI to the following:
https://<your-capsule-id>.oauth.aibixby.com/auth/external/cb
Replace <your-capsule-id>
with your encoded capsule ID, with the -
dash character in place of the .
period character. For example, if your capsule ID is example.dice
, your redirect URI would be https://example-dice.oauth.aibixby.com/auth/external/cb
.
You can also have multiple global
OAuth specifications per capsule. If you do have multiple global
specifications, you must add a providerID
at the endpoint for disambiguation:
action-endpoint (...) {
...
authorization {
global(<provider id>)
}
}
You can also define local token endpoints in a JavaScript file within your capsule. These endpoints could perform work, such as parameter reformatting, before calling an external OAuth token endpoint.
This authorization
block specifies a local endpoint file, AuthEndpoints.js
, and an exported function to call within that file named tokenEndpoint
:
authorization {
user {
oauth2-authorization-code (myService) {
client-id (123-456-789)
client-secret-key (secret)
authorize-endpoint (https://api.myService.com/login/v3/oauth)
token-endpoint (AuthEndpoints.js::tokenEndpoint)
}
}
}
The AuthEndpoints.js
file might look like this:
export function tokenEndpoint(input) {
const {
$grantType,
$clientId,
$clientSecret,
$scope,
$authCode,
$redirectUri,
$refreshToken,
$codeVerifier,
} = input
const options = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
Authorization: 'Basic {' + base64.encode($clientId + ':' + $clientSecret) + '}',
},
format: 'json',
}
const params = {
grant_type: 'authorization_code',
code: $authCode,
redirect_uri: $redirectUri,
}
const response = http.postUrl('https://api.myService.com/login/v3/oauth/access', params, options)
return {
access_token: response.access_token,
expires_in: response.expires_in,
refresh_token: response.refresh_token,
}
}
If the token endpoint does return a refresh_token
, then once the access_token
is expired, the new access_token
is requested from the token endpoint with grant type: refresh_token
. So if a local token endpoint is used, it also needs to handle any refresh_token
tokens, if they are returned by the access_token
grant. You can read more about token and token management, as well as general information on OAuth 2.0 on at https://oauth.net/2/
.
The codeVerifier
is used for the PKCE, as specified in RFC 7636. Bixby will pass the code challenge S256(codeVerifier)
to your defined authorize-endpoint
; your local endpoint should pass the code verifier on to its external token endpoint.
For another example, consider an action (TestAction
) that requires OAuth authorization:
action (TestAction) {
type (Calculation)
collect {
input (input) {
type (TestConcept)
min (Required) max (One)
}
}
output (TestConcept)
}
You need to specify in your endpoints.bxb
file that this TestAction
requires OAuth authorization:
action-endpoint (TestAction) {
remote-endpoint ("{main.url}/TestPath") {
method (POST)
}
authorization {
user
}
}
The $vivContext
parameter includes the OAuth access token as accessToken
. $vivContext
is included automatically in the request body for HTTP POST requests made to remote endpoints. To include it in local endpoints, include it in the accepted-inputs
key.
OAuth access tokens will automatically be included with HTTP GET requests as long as your capsule is using runtime version 3 or later or the use-authorization-header-for-remote-endpoint-oauth
runtime flag is set.
In this example, $vivContext
is used to return the OAuth access token when a user logs off a service:
import authLib from 'lib/auth.js';
export function logout(input) {
const { $vivContext } = input;
return $vivContext.accessToken;
}
if (config.get('oauth.enable') == 'enable') {
export function authLib.getAuthorization as authorization;
}
See Authorization Errors for information on handling OAuth authorization errors in JavaScript actions.
Bixby does not currently support the OAuth 1.0 protocol. Your capsule must authenticate with OAuth 2.0 providers.