Skip to main content
Eptura Knowledge Center

Prepare to make an authorized Public API Call

Early Access

The Public API has been released to your UAT environment.

 

 

Level: Developer

The sections below describe how to obtain an access token using the JWT grant for service accounts. Each step is described at the HTTP level and with C# sample code. If you are developing your application in a language other than C#, you will be able to use this document to implement the JWT grant in the language of your choice.

HTTP/REST

Create a JWT

To view instructions on how to create a JWT in the article Create a JSON Web Token (JWT).

Sample code showing how to do this in C# is also available in the next section of this document.

The required claims to authorize with the Public API are:

Claim Expected Value
aud

Always is "https://www.eptura.com"

iat

Current Unix timestamp.

exp

Unix timestamp for a future time.

iss

URL for the target Serraview instance, for example

https://example.serraview.com/

Trailing slash is important!

sub

Service Account ID for Public API integration, available in Configuration if setup has been completed successfully.

jti

Can be anything, but needs to change with each auth request.

Get an Access Token

After your application has constructed and signed a JWT, you will need to make an HTTP POST request to https://[instance].serraview.com/oauth2/token with the following URL encoded parameters:

identity

The JWT bearer token.

Below is a raw dump of the HTTPS POST request used in an access token request (Code has been formatted to fit in the code block):

POST /oauth2/token 

Host: {instance}.serraview.com 

Content-Type: application/x-www-form-urlencoded 

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJmYWtlX2 

FjY291bnQiLCJhdWQiOiJodHRwczovL3tpbnN0YW5jZX0uc2VycmF2aWV3LmNvbS9vYXV0aDIvdG9rZW4iLCJleHAiOjE0MTc1MDQwMzksIm5iZiI6MTQxNzUwMDQzOX0.mGJ 

sOlw5S1yG9iEkHiNn8WErhjDvidy4-jhlTVjO62o3yg5MXNcD45EYfDPDUZBlaWztHgiotz9zfNQrVTF-heqRHNVHkLgU7QH4aufIkjNbJ-PFNDv9WGCeKPm8_ 

tCcQqCSRE55-19EehSplGNb3XUrRthjA_LlGNlsRwo8U

If the token request is successful, the Authorization Server will respond with a JSON object including your access token:

{ 

"token" : "1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M"

}

C#

After you obtain the client id and private key from Serraview, use the BouncyCastle library (https://www.nuget.org/packages/BouncyCastle/) to create a JWT. First, install the following nuget packages.

Install-Package BouncyCastle -version 1.8.1 

Install-Package System.IdentityModel.Tokens.Jwt -version 4.0.1 

Install-Package Newtonsoft.Json -version 10.0.3

Create a JWT

Then add the following code to get the server URL, private key, and client id and use them to form a JWT:

string privateKey; 

try 

{ 

privateKey = File.ReadAllText(privateKeyFilePath); 

} 

catch (Exception ex) 

{ 

Console.Error.Write( 

$"Couldn't read {privateKeyFilePath}. Error: {ex}"); 

return; 

} 

// Convert PEM to RSA using the BouncyCastle library. 

var rsa = new RSACryptoServiceProvider(); 

RSAParameters rsaParameters; 

using (var privateKeyReader = new StringReader(privateKey)) 

{ 

var pemReader = new PemReader(privateKeyReader); 

var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject(); 

var privKey = (RsaPrivateCrtKeyParameters) keyPair.Private; 

rsaParameters = DotNetUtilities.ToRSAParameters(privKey); 

} 

rsa.ImportParameters(rsaParameters); 

// The only signing algorithm supported by the 

// Serraview Authorization Server is RSA using SHA-256 

// hashing algorithm. 

var signingKey = new RsaSecurityKey(rsa); 

var signingCredentials = new SigningCredentials( 

signingKey, 

SecurityAlgorithms.RsaSha256Signature, 

SecurityAlgorithms.Sha256Digest); 

// Get client id. This will be used as the issuer for the JWT. 

Console.Write("Client Id:"); 

var clientId = Console.ReadLine(); 

// Get audience for the JWT. This will be the url for the 

// authorization server we request an access token from. 

string serraviewUri; 

Uri uri; 

do 

{ 

Console.Write("Serraview Server (i.e. 

https://acme.uat.serraview.com):
"); 

serraviewUri = Console.ReadLine(); 

} while(!Uri.TryCreate(serraviewUri, UriKind.Absolute, out uri)); 

Uri audience; 

if (!Uri.TryCreate(uri, "/oauth2/token", out audience)) 

{ 

Console.Error.WriteLine($"Failed to create audience for {uri}"); 

return; 

} 

// Build JWT 

var jwt = new JwtSecurityToken( clientId, audience.ToString(), extraClaims, DateTime.UtcNow /not before/, DateTime.UtcNow.AddMinutes(5) /expires/, signingCredentials);  

// Serialize our jwt object to an actual JWT string  

var jwtString = new JwtSecurityTokenHandler().WriteToken(jwt); 

Request an Access Token

Now that you have constructed a JWT, you will use this to request an access token.

// Serraview servers require TLS1.2
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 |
SecurityProtocolType.Tls |
SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls12;
string accessToken;
using (var client = new HttpClient())
{
client.BaseAddress = uri;
var content = new FormUrlEncodedContent(
new []
{
new KeyValuePair<string, string(
"grant_type",
"urn:ietf:params:oauth:grant-type:jwt-bearer"),
new KeyValuePair>string, string>("assertion", jwtString)
});
var response = client.PostAsync("/oauth2/token", content)
.GetAwaiter().GetResult();
var result = response.Content.ReadAsStringAsync()
.GetAwaiter().GetResult();
dynamic parsedJson = JsonConvert.DeserializeObject(result);
accessToken = parsedJson["access_token"];

Ruby

After you obtain the account ID and private key from Serraview, use the ruby-jwt library to create a JWT. First, install the following gems:

gem install openssl gem install jwt

Create a JWT

The add the following code to get the server URL, private key, and client id and use them to form a JWT:

require 'openssl' 
require 'jwt' 
require 'uri' 
# helper to generate auth tokens for testing, should be runnable in IRB (no Rails required) 
def sv_public_jwt(req_id, private_key, host, svc_account_id, body_overrides: {}, head_overrides: {}) 
    kid = JWT::JWK.create_from(private_key).export[:kid] # make sure kid always matches key 
    JWT.encode( 
        { 
            aud: 'https://www.eptura.com', # client needs to know this 
            iat: Time.now.to_i, # can be nil! 
            exp: Time.now.to_i + 3600, # regardless of setting, tokens last an hour. But this needs to be set to something less than an hour 
            iss: host, # target SV instance 
            sub: svc_account_id, # public ID of service account used for auth 
            jti: req_id, # definitely needed, but can be basically anything as long as it's not repeated 
            }.merge(body_overrides).compact, # body 
            private_key, # client owns this 
            'RS256', 
            { 
              kid: kid, # not strictly needed, but helps debugging to attach it 
              alg: 'RS256', 
              }.merge(head_overrides).compact 
             ) 
end 

print "Private key path: " 
keyin = gets.chomp 

begin 
    pk = OpenSSL::PKey::RSA.new(File.read(keyin)) 
rescue Errno::ENOENT => e 
    puts "Could not find key file: #{e.message}" 
    exit 
rescue OpenSSL::PKey::RSAError => e 
    puts "Failed to parse RSA Private Key, aborting" 
    exit 
rescue => e 
    puts "Unkown error: #{e}" 
    exit 
end 

unless pk.private? 
    puts "Need a private key for signing, not a public key!" 
    exit 
end 

url_in = '' 
while !url_in.match?(URI::regexp) 
    print "Target instance URL: " 
    url_in = gets.chomp 
end 

print "Service account ID: " 
account_id = gets.chomp 

print "Token ID: " 
token_id = gets.chomp 

puts "Your token is:" 
puts sv_public_jwt(token_id, pk, url_in, account_id)

Request an Access Token

Now that you have constructed a JWT, you will use this to request an access token.

target_instance = 'https://qa1.tst.serraview.com' 
jwt = 'eyJraWQiOiJlNTQ1OGI2MWI1MGIwYTBhYTc4Y2Y1YjEwMjdkMmY0ZjMxMWVhYWIzNGM2ZDE4YjZhOTg2YTBjZGYwOWNlNzk2IiwiYWxnIjoiUlMyNTYifQ.eyJhdWQiOiJodHRwczovL3d3dy5lcHR1cmEuY29tIiwiaWF0IjoxNzI5MjA2NzkyLCJleHAiOjE3MjkyMTAzOTIsImlzcyI6Imh0dHBzOi8vcWEyNi50c3Quc2VycmF2aWV3LmNvbS8iLCJzdWIiOiJhc2RmIiwianRpIjoiMSJ9.oRIboTI-oKpBMid6P39TDPpw0g2-XYbcSoCKt0to5MTEKUO3aryo_PFb2t73EgnE6mFgNddNF-tNuwTxUShaZrW-WOjRPaCTvOBvK23WCmK6DpR1q9Mj3xz3Ap8E314R36krAgx2eq0essYFmjfh2VihX2CbuNrh2_j-3MSnlkJ_dPiPNHsGpjvjM6WDK5-Ox69xbAufZ8lz1kk0k9D1m54K6qXATaqWAc-S6ox_yuwU6SBpUZ0n-0MuF7_Fjt1S072TMDPljaYViFp8YJdsVzSo8DgtIyDMV7qAMNyxaDppTNfsjRzJOYEOLoR_Z73xHHRhwRj-AeQPBrIIL9zy8A' 

uri = URI.join(target_instance, 'public_api/v1/auth') 
req = Net::HTTP::Post.new(uri) 
req['Content-Type'] = 'application/x-www-form-urlencoded' 
req.body = "identity=#{jwt}" 

res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) } 

if res.is_a? Net::HTTPSuccess   
    token = JSON.parse(res.body)['token'] 
else   
    raise "Could not get auth token. Response code: #{res.code}, message: #{res.body}" 
end

Call Serraview APIs


This describes how to use an access token to call a Serraview API, with examples showing the details of the HTTP request and an example of how to construct the request in C#. In the examples we are calling the whoami endpoint.

HTTP/REST

After your application obtains an access token, you can use the token to make calls to the Serraview API. To do this, include the access token in a request to the API by including an Authorization: Bearer HTTP header.

GET /api/v2/whoami HTTP/1.1 

Authorization: Bearer 1/8xbJqaOZXSUZbHLl5EOtu1pxz3fmmetKx9W8CV4t79M 

Host: {instance}.serraview.com

C#

string userName; 

using (var client = new HttpClient()) 

{ 

client.BaseAddress = uri; 

// Put the access token in the Authorization request header 

// as a bearer token to authenticate the API call. 

var authHeader = new AuthenticationHeaderValue("Bearer", accessToken); 

client.DefaultRequestHeaders.Authorization = authHeader; 

var accept = new MediaTypeWithQualityHeaderValue("application/json"); 

client.DefaultRequestHeaders.Accept.Add(accept); 

var response = client.GetAsync("/api/v2/whoami") 

.GetAwaiter().GetResult(); 

var result = response.Content.ReadAsStringAsync() 

.GetAwaiter().GetResult(); 

dynamic parsedJson = JsonConvert.DeserializeObject(result); 

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="b4533627-9ee7-4d97-b6c4-7444ba9d733b"><ac:plain-text-body><![CDATA[userName = parsedJson["username"]; 
]]></ac:plain-text-body></ac:structured-macro>

} 

Console.WriteLine($"Hello {userName}");

Ruby

uri = URI.join(base_uri, 'public_api/whoami') 
req = Net::HTTP::Get.new(uri) req['Authorization'] = "Bearer #{jwt}" 

res = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') { |http| http.request(req) } 

JSON.parse(res.body)