Prepare to make an authorized Public API Call
- Last updated
- Save as PDF
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)