post https://{talkdesk-account-name}.talkdeskid.com/oauth/token
Access token request - get a new access token
Europe (EU) and Canada (CA) Base URLs
EU - https://{talkdesk-account-name}.talkdeskid.eu/oauth/token
CA - https://{talkdesk-account-name}.talkdeskidca.com/oauth/token
Client Authentication
The requests made to the token service must be authenticated using a signed JWT assertion (as per the private_key_jwt
mechanism of OpenID Connect):
require 'jwt'
require 'securerandom'
key = '<client_private_key>'
pem_key = key.scan(/.{1,64}/).tap do |lines|
lines.unshift "-----BEGIN PRIVATE KEY-----"
lines.push "-----END PRIVATE KEY-----"
end.join("\n")
private_key = OpenSSL::PKey::EC.new pem_key
payload =
{
"jti": SecureRandom.uuid,
"iss": "<client_id>",
"sub": "<client_id>",
"aud": "https://<account_name>.talkdeskid.com/oauth/token",
"iat": Time.now.to_i,
"exp": Time.now.to_i + 5*60
}
token = JWT.encode payload, private_key, '<client_key_algorithm>', {"kid": "<client_key_id>"}
package com.talkdesk.example;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.time.Instant;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
public class GenerateClientAssertion {
public static void main(String... args) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
String key = "<client_private_key>";
// Replace EC with ECDSA if BouncyCastle is enabled
PrivateKey privateKey = KeyFactory.getInstance("EC")
.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key)));
String token = Jwts.builder()
.setHeaderParam("kid", "<client_key_id>")
.setId(UUID.randomUUID().toString())
.setIssuer("<client_id>")
.setSubject("<client_id>")
.setAudience("https://<account>.talkdeskid.com/oauth/token")
.setIssuedAt(new Date())
.setExpiration(Date.from(Instant.now().plusSeconds(300)))
.signWith(SignatureAlgorithm.<client_key_algorithm>, privateKey)
.compact();
}
}
# Requires the 'PyJWT' and 'cryptography' packages to be installed
import uuid
import jwt
from datetime import datetime, timedelta
# Client Private Key
CLIENT_PRIVATE_KEY = "<client_private_key>"
CLIENT_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" + CLIENT_PRIVATE_KEY + "\n-----END PRIVATE KEY-----"
# JWT Headers
headers = {"kid": "<client_key_id>"}
# JWT Payload
payload = {"iss": "<client_id>",\
"sub": "<client_id>",\
"aud": "https://<account_name>.talkdeskid.com/oauth/token",\
"jti": str(uuid.uuid4()),\
"exp": datetime.utcnow() + \
timedelta(seconds=300),\
"iat": datetime.utcnow()}
# Signed JWT
jwt_token = jwt.encode(payload, CLIENT_PRIVATE_KEY, algorithm = "<client_key_algorithm>", headers = headers)
(require
'[clj-time.core :as time]
'[buddy.sign.jwt :as jwt]
'[buddy.core.keys :as keys])
(def token
(jwt/sign
{:jti (str (java.util.UUID/randomUUID))
:iss "<CLIENT_ID>"
:sub "<CLIENT_ID>"
:aud "https://taiga.talkdeskid.com/oauth/token"
:exp (time/plus (time/now) (time/minutes 5))
:iat (time/now)}
(keys/private-key "<CLIENT_PRIVATE_KEY_FILE>")
{:alg :es256
:kid "<CLIENT_KEY_ID>"}))
// Requires the 'jsonwebtoken' and 'uuid' packages to be installed
var jwt = require('jsonwebtoken');
var uuid = require('uuid/v4');
var private_key = '<client_private_key>'
private_key = "-----BEGIN PRIVATE KEY-----\n" + private_key + "\n-----END PRIVATE KEY-----"
var header = {
kid: '<client_key_id>'
}
var payload = {
iss: '<client_id>',
sub: '<client_id>',
aud: 'https://<account_name>.talkdeskid.com/oauth/token',
jti: uuid(),
exp: Math.floor(Date.now() / 1000) + 300,
iat: Math.floor(Date.now() / 1000)
}
token = jwt.sign(payload, private_key, {header: header, algorithm: '<client_key_algorith>'})
Signed JWT - Expiration
You will get an
invalid_client
error message if your signed JWT has expired.In the example above, the signed JWT expires after five minutes. If you wish to have a signed JWT with a longer expiration date, you can change it via the
exp
and/orsetExpiration
variables.
Body Response - Schema
200 (the access token - and optional refresh token - generated, along with some additional properties about the authorization)
Parameter | Type | Description | Required |
---|---|---|---|
access_token | string | the access token | yes |
token_type | string | The type of token to be specified in the authorization header. Default: Bearer . | yes |
expires_in | integer | duration of time (seconds) the access token is granted for | yes |
scope | string | A space-separated list of scopes (URL encoded) the client requested access to. If the "scope" parameter is not provided in the request body parameter, the returned value will be the list of scopes the client granted. | yes |
refresh_token | string | The refresh token used to obtain another access token. Required only when using "authorization_code" and "refresh_token" grant types. | no |
sid | string | The refresh token used to obtain another access token. Required only when using "authorization_code" and "refresh_token" grant types. | no |
id_token | string | The ID token (OpenID Connect functionality to return information about the authentication performed during the authorization code flow). Required only when using the "authorization_code" grant type and if "openid" scope was included in the "scope" parameter provided in the "/oauth/authorize" request query parameter. | no |
400 (bad request), 401 (unauthorized)
Parameter | Type | Description | Required |
---|---|---|---|
error | string | n/a | yes |
error_description | string | n/a | yes |
Troubleshooting
If you have questions or technical issues, please open a ticket using this form.