Auth Schemes

Use JSON Web Tokens to make secure requests to Elements APIs without the need for authentication or user credentials.

Auth Schemes allow third party applications to make server-to-server calls to the Elements APIs without needing to login or supply user credentials. Auth Schemes leverage the use of JWTs to accomplish the task.

In addition to creating user credentials, it is possible to use the signed JWTs to transparently sync user account information with existing services.

Once imported via auth scheme, users within Elements have the same privileges as if they had signed up directly with Elements. Furthermore, it is possible to provide short term API keys directly to a web app, thereby removing the need to use direct server to server calls in favor of having the page call Elements directly.

For help creating an auth scheme, see Generating Auth Schemes below.

Creating a JWT From Third Party Code

Once you have defined your Auth Scheme in the console, you may use the private key associated with the scheme to make direct API calls.

The basic process for using the auth scheme to generate API keys is as follows:

  1. Define an auth scheme. Either supply or allow Elements to generate a public/private key pair.

  2. Import the private key pair into your existing web application. Ideally using your cloud provider's secure credential storage.

  3. Generate a signed JWT using the private key associated with the auth scheme on your server application.

  4. Once you have the signed JWT, you may use the token in one of two ways:

    1. Return the signed JWT to the web or mobile application via API call and allow the page or the application to make direct calls to Elements APIs.

    2. Directly call the Elements APIs from the server application.

Never share the JWT Private Key with the client application. The private key is sensitive information and should always be treated as such.

Constructing the JWT

In order to successfully use the auth scheme, you must supply certain claims with the JWT. This supplies the information necessary for Elements to match the user to its own internal database.

Standard JWT Claims

The following section lists the standard JWT claims that Elements understands and how it interprets each claim when making a request.

Refer to RFC-7519 Section 4.1 for a detailed explanation of standard registered claims.

iss - Issuer

iss represents the issuer of the token. This should be a valid identifier for your application. See the Application API for more information. If specified, this must match the unique name of an Application configured within Elements.

aud - Audience

aud represents the Audience. In the context of the Elements security model, this must match the configured auth scheme. If no configured auth scheme matches, then the server will fail the request.

exp - Expiration

exp represents the expiration date. Elements will reject any token which has expired. If left unspecified, the token will last indefinitely.

We do not recommend using permanent tokens as it creates a security vulnerability within your app.

sub - Subject

sub (or subject). This is the literal value used to key the user. See the elm_userkey below for more information.

Private Claims

In addition to standard JWT claims, Elements supports the following private claims. For more information on Private Claims, see RFC-7519 Section 4.3. Elements prefixes all claims with elm_ to avoid collisions with other private claim names.

elm_atype - Elements Auth Type

This is required in all cases and must be the literal value custom. This is intended to be future-proof as Elements may support multiple auth scheme configurations in the future based on changing requirements and needs.

elm_userkey - Elements User Key

This is required in all cases and must contain the key of the user model through which Elements will uniquely identify the user. The supported values are as follows.

  • email - the user’s email address.

  • name - the user’s unique username.

  • facebookId - The user’s Facebook ID.

  • firebaseId - The user’s Firebase ID.

  • appleSignInId - The user's Apple Sign-In ID.

  • externalUserId - The user's external user ID.

In most cases, we recommend passing your user's primary database ID to externalUserId , which will avoid name or email conflicts in case users change or update their email addresses within your web application.

elm_user - Elements User

This is a full JSON document containing a User object. See Users and Profiles and the Swagger documentation for the contents of this document.

Upon receipt of the JWT containing this document, Elements will automatically sync the user information from the supplied document. In order to avoid excessive round-trip database traffic, Elements may opt to pool, batch, or otherwise delay updates to its own database when processsing JWT requests. However, the entire user document must exist in the JWT.

Generating Auth Schemes Using the Console

Generating an Auth scheme consists of creating or supplying a public/private key pair and configure the additional metadata in the auth scheme. To begin, open the Elements admin panel and find the section labeled Auth.

  1. Navigate to the Auth Tab.

  2. Find the button at the top of the Auth Scheme list labeled "Create Auth Scheme"

Now you will see the create auth scheme dialog

Fill out the following fields:

  1. Audience (Name) indicates the matching "aud" field of the JWT. This follows the Name paradigm.

  2. Allowed Issuers is a list of allowed issuers - This is a list of one or more Applications that may support this Auth Scheme. If not tied to a specific Application, then leave this blank. See Applications for more information on the value here.

  3. Tags - This follows the Tags paradigm for Auth Schemes.

  4. User Level - This is the maximum user level that the scheme will allow when creating new users in Elements.

  5. Algorithm - This is the signing algorithm used to verify the authenticity of the JWT. Supported algorithms include:

  6. Public Key - If supplying your own Public key, then paste it here.

  7. Alternatively, if you want Elements to generate the key pair, select the "Generate Key" option in the upper right corner.

The Public Key follows the Java DER format of public keys.

Viewing Generated Key

If you selected the "Generate Key" option, then you will be presented with the public and private key pair.

Elements does not store the private key, so be sure to store the private key securely. .

Updating Auth Scheme

Updating an auth scheme is a simple process and operates similarly to the auth creation process.

  1. Navigate to the Auth Tab.

  2. Find the Auth Scheme you wish to edit, and select "Edit"

Within the Auth Scheme editor, you will see a dialog which will allow you to edit the audience, issuers, tags, and levels.

All the same fields apply from the auth generation process above.

If you want Elements to regenerate the key pair, select the "Generate Key" option in the upper right corner.

If you regenerate or update the public key, all existing JWTs will be immediately invalidated. Elements does not keep track of key history.

Key Format

Elements is based in Java. Therefore, it supplies keys in formats supplied by the JVM. For easy transport, Elements encodes all keys in base64. In order to import the keys into other applications, it may be necessary to convert to other formats using tools like OpenSSL. This section describes a few use cases in handling the keys.

  • For Public keys, refer to X509EncodedKeySpec detailed documentation.

  • For Private keys, refer to PKCS8EncodedKeySpec for detailed documentation.

  • Elements encodes all keys in base64 format using ASCII-compatible encoding.

Example Public RSA Key:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvD1Iz3zf+MmMTT9Ugovovslyq7Kb/mKPLNlC8KKAH/QhNwuYbLgJclzZ4rySFTxMYRsGxIE1mTDorOhqKhk8WekVJFwPLEVDuP4ABU7QSJeZGnevtCxNC4VYB8ZbI68a1Rm2OFdhiu7cObVNdVioqtW58mltLmIeSHj8gRQKKVDBl4B6xnR1NWvQlvZS7mhBKC4yFP8fM6ihTyhjhkkTeoZrPWZSjaJT0aDdK9n0Cdm3Exr3pN7Fr8TtOl+XHpZ45VXEJqcCBnJHRMTdnfaITkphBDgyiAhAGUGIDQsz/aVEzhTUt7ZIne29faeZ7H7K9GCu+I2E1coNHRZvFDjvPwIDAQAB

Example Private RSA Key

MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8PUjPfN/4yYxNP1SCi+i+yXKrspv+Yo8s2ULwooAf9CE3C5hsuAlyXNnivJIVPExhGwbEgTWZMOis6GoqGTxZ6RUkXA8sRUO4/gAFTtBIl5kad6+0LE0LhVgHxlsjrxrVGbY4V2GK7tw5tU11WKiq1bnyaW0uYh5IePyBFAopUMGXgHrGdHU1a9CW9lLuaEEoLjIU/x8zqKFPKGOGSRN6hms9ZlKNolPRoN0r2fQJ2bcTGvek3sWvxO06X5celnjlVcQmpwIGckdExN2d9ohOSmEEODKICEAZQYgNCzP9pUTOFNS3tkid7b19p5nsfsr0YK74jYTVyg0dFm8UOO8/AgMBAAECggEAP8mEosruGqAxqvuK57IBbKVW9lfQBKPhYJE+3cwzHqDboIuNW0oB6X8NVogP+KI2P7Go2W3ve7nXHsCjOSDUEqOpRmjru1S9XjK0Txgl/HNirlVgdO2OLhlBe2D8AVuU/CF6Xh0+MJZAik2lsd4ZScqi+EJBfTZCjMxyxErGJrlhJt0y7Gtfo9psWzZcNnDyBL+DYfsKyyU6VEpcK5i3Amo+bGGV4bK04m2UcOCjSCPlcSxZQERp1/aUoRDZ/c8CbdSBynNiUVFz8vek5sM4e/BlfYBUgmfsnBkYC1WFognSMPJi7J5mgnb7PIKHTVcJ4GDUv6R5GOsde3RROCfsAQKBgQD1wm6A0Nyf+WnxvfKBZ89MsiA95+3fWa55kFzLOHD5mDIzn9hEOtnJGfrkoRLhfwAgQCL3PYM4F9fbG6qkbHAmc9Kds6n7IMaXVf6EBhMMZ1O7jQ+kn7L4YRtPC8nD8r0qGliGkqQ2HVsikKha/bPgv4CnJDJ4NqVZBB9zP+44GQKBgQDEFUYPPkgERmd+UlgFY8V9zUaqwKLO53DeyFT+96e/kMr8VZ+8ZSDP0oxBOn0QmMjVSkePA2tMWBsI/o0qmJfu4h++EbrZ1w58PTY2kYYqwlek77a7ndx8Damt4zhjmR1br0Gb/Td6JX08oz9i5lPegF8MnpPwnfz5vUdAqlGtFwKBgDJJYJcXJa3OOTFv7okwFqjY4eQI6xGCpkLVmUcz+1n3HH6XvIbpi9qsaDwUAWsGs53lwcHZYlo99rssxBP05FXZ6US/mI58PGaHABc/rvIgym9cA9FppBNSu2XHQbfImZBd57NRmixAgX9nHivQMdhRFyAcNf+HHvpB77WDZVkxAoGAdn40nDmS46J4IEo6judADUnjjoRi3o3WE4sUcg/O+2DQibRkl0C1l2ExCKoDsefiVaJRpAb47GXB0KmjPT6BcgaMEBw+wi3HvyRugoNmhKh0tmN2FeLLvtuy0jYheW6p4yIBj/ZxdAr7p40vXOC7hhYlWkbqN9oBahoL2PQT73kCgYEArMJWc2FFj7NjwJvrUVg0/PxKd5WkE7vlHHaztD1YBrPgNYkaB73aadO75N8go7WEIRCXwjhESGey/zfcAhxj4gTaJIZd9lOd1Mkp+Z5wcuTdm5yieMAGeo+k4UZwjeLT/XPYrlPr3oNVstAJv4eHQpDDvRbVbQcJEqJU/eEkY3Q=

JVM Based Applications

If using Java, Kotlin, or any other JVM based language, Elements keys will integrate seamlessly with a simple conversion. The following demo program shows how the keys can be used to encrypt and decrypt messages.

When using JVM based languages, we recommend using the Auth0 Java JWT library because it has been tested and known to work with Elements. However, we have tested that our JWTs follow the standard specification, so any JWT library should work correctly.

package com.namazustudios.socialengine;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class TestKeys {

   private static final String PUBLIC =
           "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvD1Iz3zf+MmMTT9Ugovo" +
           "vslyq7Kb/mKPLNlC8KKAH/QhNwuYbLgJclzZ4rySFTxMYRsGxIE1mTDorOhqKhk8" +
           "WekVJFwPLEVDuP4ABU7QSJeZGnevtCxNC4VYB8ZbI68a1Rm2OFdhiu7cObVNdVio" +
           "qtW58mltLmIeSHj8gRQKKVDBl4B6xnR1NWvQlvZS7mhBKC4yFP8fM6ihTyhjhkkT" +
           "eoZrPWZSjaJT0aDdK9n0Cdm3Exr3pN7Fr8TtOl+XHpZ45VXEJqcCBnJHRMTdnfaI" +
           "TkphBDgyiAhAGUGIDQsz/aVEzhTUt7ZIne29faeZ7H7K9GCu+I2E1coNHRZvFDjv" +
           "PwIDAQAB";

   private static final String PRIVATE = 
           "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8PUjPfN/4yYxN" +
           "P1SCi+i+yXKrspv+Yo8s2ULwooAf9CE3C5hsuAlyXNnivJIVPExhGwbEgTWZMOis" +
           "6GoqGTxZ6RUkXA8sRUO4/gAFTtBIl5kad6+0LE0LhVgHxlsjrxrVGbY4V2GK7tw5" +
           "tU11WKiq1bnyaW0uYh5IePyBFAopUMGXgHrGdHU1a9CW9lLuaEEoLjIU/x8zqKFP" +
           "KGOGSRN6hms9ZlKNolPRoN0r2fQJ2bcTGvek3sWvxO06X5celnjlVcQmpwIGckdE" +
           "xN2d9ohOSmEEODKICEAZQYgNCzP9pUTOFNS3tkid7b19p5nsfsr0YK74jYTVyg0d" +
           "Fm8UOO8/AgMBAAECggEAP8mEosruGqAxqvuK57IBbKVW9lfQBKPhYJE+3cwzHqDb" +
           "oIuNW0oB6X8NVogP+KI2P7Go2W3ve7nXHsCjOSDUEqOpRmjru1S9XjK0Txgl/HNi" +
           "rlVgdO2OLhlBe2D8AVuU/CF6Xh0+MJZAik2lsd4ZScqi+EJBfTZCjMxyxErGJrlh" +
           "Jt0y7Gtfo9psWzZcNnDyBL+DYfsKyyU6VEpcK5i3Amo+bGGV4bK04m2UcOCjSCPl" +
           "cSxZQERp1/aUoRDZ/c8CbdSBynNiUVFz8vek5sM4e/BlfYBUgmfsnBkYC1WFognS" +
           "MPJi7J5mgnb7PIKHTVcJ4GDUv6R5GOsde3RROCfsAQKBgQD1wm6A0Nyf+WnxvfKB" +
           "Z89MsiA95+3fWa55kFzLOHD5mDIzn9hEOtnJGfrkoRLhfwAgQCL3PYM4F9fbG6qk" +
           "bHAmc9Kds6n7IMaXVf6EBhMMZ1O7jQ+kn7L4YRtPC8nD8r0qGliGkqQ2HVsikKha" +
           "/bPgv4CnJDJ4NqVZBB9zP+44GQKBgQDEFUYPPkgERmd+UlgFY8V9zUaqwKLO53De" +
           "yFT+96e/kMr8VZ+8ZSDP0oxBOn0QmMjVSkePA2tMWBsI/o0qmJfu4h++EbrZ1w58" +
           "PTY2kYYqwlek77a7ndx8Damt4zhjmR1br0Gb/Td6JX08oz9i5lPegF8MnpPwnfz5" +
           "vUdAqlGtFwKBgDJJYJcXJa3OOTFv7okwFqjY4eQI6xGCpkLVmUcz+1n3HH6XvIbp" +
           "i9qsaDwUAWsGs53lwcHZYlo99rssxBP05FXZ6US/mI58PGaHABc/rvIgym9cA9Fp" +
           "pBNSu2XHQbfImZBd57NRmixAgX9nHivQMdhRFyAcNf+HHvpB77WDZVkxAoGAdn40" +
           "nDmS46J4IEo6judADUnjjoRi3o3WE4sUcg/O+2DQibRkl0C1l2ExCKoDsefiVaJR" +
           "pAb47GXB0KmjPT6BcgaMEBw+wi3HvyRugoNmhKh0tmN2FeLLvtuy0jYheW6p4yIB" +
           "j/ZxdAr7p40vXOC7hhYlWkbqN9oBahoL2PQT73kCgYEArMJWc2FFj7NjwJvrUVg0" +
           "/PxKd5WkE7vlHHaztD1YBrPgNYkaB73aadO75N8go7WEIRCXwjhESGey/zfcAhxj" +
           "4gTaJIZd9lOd1Mkp+Z5wcuTdm5yieMAGeo+k4UZwjeLT/XPYrlPr3oNVstAJv4eH" +
           "QpDDvRbVbQcJEqJU/eEkY3Q=";

   public static void main(final String[] args) throws Exception {

      final String message = "Hello Encrypted World!";
      final byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);

      final byte[] publicKeyBytes = Base64.getDecoder().decode(PUBLIC);
      final byte[] privateKeyBytes = Base64.getDecoder().decode(PRIVATE);

      final X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes, "RSA");
      final PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes, "RSA");

      final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      final PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
      final PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

      final Cipher ecCipher = Cipher.getInstance("RSA");
      ecCipher.init(Cipher.ENCRYPT_MODE, publicKey);

      final byte[] encryptedMessageBytes = ecCipher.doFinal(messageBytes);
      ecCipher.init(Cipher.DECRYPT_MODE, privateKey);

      final byte[] decryptedMessageBytes = ecCipher.doFinal(encryptedMessageBytes);
      final String decryptedMessage = new String(decryptedMessageBytes, StandardCharsets.UTF_8);

      if (!message.equals(decryptedMessage)) {
         throw new IllegalArgumentException("Something wen wrong.");
      }

   }

}

Last updated