If you haven’t already, check out our high-level summary for authentication with Redox. If you want to authenticate with a JSON web token (JWT), follow the steps below.
This authentication method is currently only supported for the Redox FHIR® API and the Redox Platform API.
In order to authenticate with a JWT, you must have a key pair with a private and public key. There are two ways to get a generate a public key:
This type of URL publicly exposes the keys you use for signing your JWT. The URL can be internal to your servers or somewhere like a GitHub Gist. If you use this URL, Redox fetches the kid
property in the JWT to find the right public key.
Make sure to copy or download the private key prior to closing the modal. You can't retrieve the private key again after leaving this screen.
You have two options for requesting an access token:
Either way, the authentication steps are the same. If you choose to use Postman, complete the prep steps that we outline below. Otherwise, skip to the authentication steps.
If you choose to use Postman, there's a little bit of setup you need to do before running the authentication requests. Make sure that you downloaded the Postman environment from step #10 in the previous section.
secret_value
. In in the Initial Value column, paste your secret value.
Currently, this Postman authentication collection only supports your secret if it's JWK encoded.
If you do have a JWK encoded secret value, you can easily copy and paste it into Postman so that the keys and secret values automatically populate. To do this, copy your secret value and paste it into the "key" field in Postman.
Now that Postman is ready, you can proceed to the authentication steps.
To give you an overview of how this works, you generate a signed request and send it via HTTP POST from your system. Redox validates the signature in the request, then sends back a response with the access token. You use this access token to make an API request to Redox.
Just note that the access token we provide to you expires after 5 minutes. You can use this access token to make any API requests within 5 minutes, but if a request fails, it's likely that your access token has expired. You must send a new authentication request to generate a new access token.
If you have high traffic and don't want to disrupt your workflow, you can use a service to refresh your access token every 5 minutes.
If you have low traffic, you can run an authentication request prior to making any API request.
Parameter | Required | Description |
---|---|---|
alg | Y | The JWA algorithm used for signing the authentication JWT. Note that we currently only support RS384 . |
kid | Y | The identifier of the key-pair used to sign this JWT. This identifier tells us which public key to use to verify the JWT. |
typ | Y | This is the type of token request. Populate this with JWT . |
jku | N | This field may be populated if you provided a JWKS URL in the Dashboard. If you provide it here, the URL should match what's saved in the Dashboard. Populate this with the TLS-protected JWKS URL, which contains the public key(s) that are accessible without authentication or authorization. If this field isn't present, Redox reverts to what's saved in the Dashboard. |
{"alg": "RS384","kid": "some-key-id","typ": "JWT"}
Parameter | Required | Description |
---|---|---|
iss | Y | The issuer of the JWT. This should be populated with the client_id of the key you created in the Dashboard. Keep in mind that this is the same value that's provided for the sub claim. |
sub | Y | This should be populated with the client_id of the key you created in the Dashboard. Keep in mind that this is the same value that's provided for the iss claim. |
aud | Y | The audience of the JWT. This should be populated with https://api.redoxengine.com/v2/auth/token . |
iat | Y | The UTC timestamp for when the JWT was created (e.g.,1970-01-01T00:00:00Z UTC). This time must not be greater than 5 before exp below. |
exp | Y | The expiration UTC timestamp for the JWT (e.g., 1970-01-01T00:00:00Z UTC). This time must not be greater than 5 minutes in the future. |
jti | Y | This is a nonce string value that uniquely identifies this JWT. Redox denies requests if the jti is reused within the lifetime of the JWT. |
{"iss": "[client ID of your API key - created in the dashboard]","sub": "[client ID of your API key - created in the dashboard]","aud": "https://api.redoxengine.com/v2/auth/token","iat": Math.floor(date.getTime() / 1000),"exp": Math.floor(date.getTime() / 1000) + 300 ,"jti": randomBytes(8).toString('hex')}
https://api.redoxengine.com/v2/auth/token
.
If you're using Postman, send the authentication request via HTTP POST
. For the header, use content-type application/x-www-form-urlencoded
. Then populate the request with the following parameters:
Parameter | Required | Description |
---|---|---|
grant_type | Y | Populate this with client_credentials . |
client_assertion_type | Y | Populate this with urn:ietf:params:oauth:client-assertion-type:jwt-bearer . |
client_assertion | Y | Populate this with the signed authentication JWT value, which you generated in the previous steps. |
curl --location --request POST 'https://api.redoxengine.com/v2/auth/token' \--header 'Content-Type: application/x-www-form-urlencoded' \--data-urlencode 'grant_type=client_credentials' \--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \--data-urlencode 'client_assertion=eyJhbGciOiJSUzM4NCIsImtpZCI6InJlZG94LWRvY3VtZW50YXRpb24iLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJsaXB0YS1sZWUtODczMiIsInN1YiI6ImxpcHRhLWxlZS04NzMyIiwiYXVkIjoiaHR0cHM6Ly9hcGkucmVkb3hlbmdpbmUuY29tL3YyL2F1dGgvdG9rZW4iLCJpYXQiOjE2MDIyNjk3NzMsImV4cCI6MTYwMjI3MDA3MywianRpIjoicmVkb3gxNjAyMjY5NzczNjUwIiwic2NvcGVzIjpbXX0.menhDYTyfxS8J2Ux7x8XHGJCnIHjcWv2yBKWGeKbmhdfoDtLnYUFNUBs57wZqHT3Zgcy8g5kMz14eQ7Xxxb7wnuOSjAqBgc5ns1f6xHHWJ97CtPwljrD1Oysh1oEIwNFbI72XffxpLUYW_e3WypZPPPw-AriWy36-6DYmot96TE9bMSZjheR0NAxlsq-ZgOYvY889kzu_fsLhobQsZNyStgSvGRLtMkv3yhHB8BrzPQGC_a6J7XKYl3OxJy0lrXMjhCWRI0Z920MOGzBjwSYUVFTj6kh9HSfDENTLHSaedKCdGoAbIvOpXYSmZv7pTq5XuFUMBu-tYw7iW3wbdsVPg'
import { JWK, JWT } from "jose";import * as axios from "axios";import { stringify } from "qs";import { randomBytes } from "crypto";// import your private key as PEM or JWKconst private_key = JWK.asKey(`-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----`);// Signing is a function of the private key and payloadexport function BackendServiceAuth(private_key: JWK.RSAKey, payload: any) {return JWT.sign(payload, private_key, {algorithm: "RS384",});}const date = new Date();// minimum set of payload propertiesconst sign_request = {iss: "lipta-lee-8732",sub: "lipta-lee-8732",aud: "https://api.redoxengine.com/v2/auth/token",iat: Math.floor(date.getTime() / 1000),exp: Math.floor(date.getTime() / 1000) + 300,jti: randomBytes(8).toString("hex"), // a random string to prevent replay attacks};// build application/x-www-url-formencoded querystringconst data = stringify({grant_type: "client_credentials",client_assertion_type:"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",client_assertion: BackendServiceAuth(private_key, sign_request), //generate JWT});// generate axios request and send to Redoxvar config = {method: "post",url: "https://api.redoxengine.com/v2/auth/token",headers: {"Content-Type": "application/x-www-form-urlencoded",},data: data,};axios(config).then(function(response) {console.log(JSON.stringify(response.data));}).catch(function(error) {console.log(error);});
import datetimeimport jwtimport requestsclass BackendServiceAuth(requests.auth.AuthBase):token = Nonedef __init__(self, auth_location, client_id, client_url, private_key):self.auth_location = auth_locationself.client_id = client_idself.client_url = client_urlself.private_key = private_keydef __call__(self, request):if not self.token:expiration = datetime.datetime.now() + datetime.timedelta(minutes=5)payload = {'grant_type': 'client_credentials','client_assertion_type':'urn:ietf:params:oauth:client-assertion-type:jwt-bearer','client_assertion': jwt.encode({'iss': self.client_url,'sub': self.client_id,'aud': self.auth_location,'exp': int(expiration.strftime('%s')),'jti': uuid4().hex,}, self.private_key, algorithm='RS384'),}response = requests.post(self.auth_location,data=payload,timeout=30)response.raise_for_status()self.token = response.json()['access_token']request.headers['Authorization'] = 'Bearer %s' % self.tokenreturn request
You can now initiate requests with the access token in the Authorization HTTP header using the Bearer authentication scheme.
curl \-X POST https://api.redoxengine.com/endpoint \-H "Content-Type: application/json" \-H "Authorization: Bearer [TOKEN]" \-d '{}'