View Source Shin

🍀 A collection of lightweight auth utilities for Elixir.

Introduction

Shin 俥 means "trust", "faith", or "belief" in Japanese.

This package aims to provide lightweight utilities that can be used to ensure that primitives are well validated and trusted for usage by auth providers.

Getting started

The package can be installed by adding shin_auth to your list of dependencies in mix.exs:

def deps do
  [
    {:shin_auth, "~> 0.1.0"}
  ]
end

Utilities per protocol

OpenID Connect (OIDC)

load_provider_configuration

Based on the spec: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata

Loads, validates and parses the Identity Provider configuration based on their discovery endpoint metadata.

With valid configuration, returns parsed metadata:

iex(1)> ShinAuth.OIDC.load_provider_configuration("https://valid-url/.well-known/openid-configuration")
{:ok, %ShinAuth.OIDC.ProviderConfiguration.Metadata{}}

With invalid configuration, returns error:

iex(1)> ShinAuth.OIDC.load_provider_configuration("https://invalid-discovery/.well-known/openid-configuration")
{:error, %ShinAuth.OIDC.ProviderConfiguration.Error{}}

Here's a list of error per tags:

TagsReason
malformed_discovery_endpoint or discovery_endpoint_unreachableThe provided endpoint is either malformed or unreachable via HTTP request
authorization_endpoint_unreachableauthorization_code is unreachable via HTTP request
token_endpoint_unreachabletoken_endpoint is unreachable via HTTP request
jwks_uri_unreachable or malformed_jwks_uri_responsejwks_uri is either unreachable via HTTP request or the response is malformed
missing_issuer_attributeissuer attribute is missing from the provider's metadata

Security Assertion Markup Language (SAML)

decode_saml_response

Parsed a given SAML response to a struct with attributes and values:

iex(1)> ShinAuth.SAML.decode_saml_response(saml_response_xml)

{:ok, %ShinAuth.SAML.Response{
   common: %ShinAuth.SAML.Response.Common{
     id: "_123",
     version: "2.0",
     destination: "https://api.example.com/sso/saml/acs/123",
     issuer: "https://example.com/1234/issuer/1234",
     issue_instant: "2024-03-23T20:56:56.768Z"
   },
   status: %ShinAuth.SAML.Response.Status{
     status: :success,
     status_code: "urn:oasis:names:tc:SAML:2.0:status:Success"
   },
   conditions: %ShinAuth.SAML.Response.Conditions{
     not_before: "2024-03-23T20:56:56.768Z",
     not_on_or_after: "2024-03-23T21:01:56.768Z"
   },
   attributes: [
     %ShinAuth.SAML.Response.Attribute{
       name: "id",
       value: "209bac63df9962e7ec458951607ae2e8ed00445a"
     },
     %ShinAuth.SAML.Response.Attribute{
       name: "email",
       value: "foo@corp.com"
     },
     %ShinAuth.SAML.Response.Attribute{
       name: "firstName",
       value: "Laura"
     },
     %ShinAuth.SAML.Response.Attribute{
       name: "lastName",
       value: "Beatris"
     },
     %ShinAuth.SAML.Response.Attribute{name: "groups", value: ""}
   ]
 }}

decode_saml_request

Parsed a given SAML request to a struct with attributes and values:

iex(1)> ShinAuth.SAML.decode_saml_request(saml_request_xml)

{:ok, %ShinAuth.SAML.Request{
   common: %ShinAuth.SAML.Request.Common{
     id: "_123",
     version: "2.0",
     assertion_consumer_service_url: "https://auth.example.com/sso/saml/acs/123",
     issuer: "https://example.com/123",
     issue_instant: "2023-09-27T17:20:42.746Z"
   }
 }}