ertugrulozcan / ErtisAuth

Open Source Identity and Access Management API
MIT License
10 stars 7 forks source link
authentication authorization ertisauth identity openid-connect

ErtisAuth

Open Source Identity and Access Management API

Get Started

ErtisAuth is a free and open-source OpenID-Connect framework and high performer identity and access management API. It's designed to provide a common way to authenticate requests to all of your applications, whether they're web, native, mobile, or Web API endpoints. It is based on the RBAC (Role based access control) and UBAC (User based access control) models for authorization/access control. ErtisAuth incorporates features needed to integrate token-based authentication, SSO and API access control in your applications for authorization and authentication. It is licensed under MIT License (an OSI approved license).

Documentation

For developer guide and API documentation, please visit wiki page.

Installation

Standalone Build & Installation on Linux, Windows or Mac OS

ErtisAuth on Docker

Make sure you have Docker installed.

Standalone Running from Docker Image

If you have a mongo database, you just run ErtisAuth with docker image. Database configuration can be pass with environment variables on the docker run command.

From a terminal start ErtisAuth with the following command:

$ docker run -p 9716:80 ertugrulozcan/ertisauth:latest

For database configuration with environment variables;

$ docker run -p 9716:80 -e Database__ConnectionString=<ConnectionString> ertugrulozcan/ertisauth:latest

Connection String Format

<DB_SCHEME>://[<DB_USERNAME>:<DB_PASSWORD>@]<DB_HOST>[:<DB_PORT>][,...hostN[:portN]][/[<DB_DATABASE>][?options]]

Working with Docker Compose

$ docker-compose up -d

This command will start ErtisAuth API exposed on the local port 9716 along with a composed MongoDB in same container. It will also create an membership (realm) an initial admin user and an application (optional) for machine to machine communication. If you wish, you can migrate whether membership, admin user, application etc resources later. For more information about the migration, look at the migration section in the documentation.


Migration

To start using ErtisAuth, you must have at least one membership and at least one user for generating tokens. To use basic authentication method, you must have an application. ErtisAuth incorporates a migration API endpoint to create basic resources such as membership and admin user and set administrator settings at the first installation. The migrate command creates these resources and configures relations and settings. The admin role will be created automatically by ErtisAuth. The database connection string must be sent in headers to checking the database authorization.


Request Model

curl --location --request POST '{{base_url}}/api/v1/migrate' \
--header 'ConnectionString: {{db_connection_string}}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "membership": {
        "name": "{{membership_name}}",
        "expires_in": {{token_life_time}},
        "refresh_token_expires_in": {{refresh_token_life_time}},
        "hash_algorithm": "{{hash_algorithm}}",
        "encoding": "UTF-8"
    },
    "user": {
        "username": "{{usernamme}}",
        "firstname": "{{first_name}}",
        "lastname": "{{last_name}}",
        "email_address": "{{email_address}}",
        "password": "{{password}}",
        "user_type": "User"
    },
    "application": {
        "name": "{{application_name}}",
        "role": "admin"
    }
}'


Health Check

Request Model

curl --location --request GET '{{base_url}}/api/v1/healthcheck'

Successful Response

Status Code : 200 OK

{
    "status": "Healthy"
}

Failed Response

Status Code : 50X (Sample unhealhty case)

{
    "status": "Unhealthy",
    "message": "Database have not migrated yet"
}


Endpoints


1. Tokens Endpoint    /tokens


Routes Method Headers Query String Body
/tokens/me GET Authorization Header - -
/tokens/whoami GET Authorization Header - -
/tokens/generate-token POST X-Ertis-Alias, X-IpAddress (optional), X-UserAgent (optional) - Username & Password payload
/tokens/verify-token GET Authorization Header - -
/tokens/verify-token POST - - Token payload
/tokens/refresh-token GET Authorization Header revoke=true (Default false) -
/tokens/refresh-token POST - revoke=true (Default false) Token payload
/tokens/revoke-token GET Authorization Header logout-all=true (Default false) -
/tokens/revoke-token POST - logout-all=true (Default false) Token payload


Login / Generate Token


Request Model

curl --location --request POST '{{base_url}}/api/v1/generate-token' \
--header 'X-Ertis-Alias: {{membership_id}}' \
--header 'X-IpAddress: {{client_ip}}' \
--header 'X-UserAgent: {{user_agent}}' \
--header 'Content-Type: application/json' \
--data-raw '{
    "username": "{{username}}",
    "password": "{{password}}"
}'

Body Model

{
    "username": "{{username}}",
    "password": "{{password}}"
}

Successful Response

Status Code : 201 Created

{
    "token_type": "bearer",
    "refresh_token": "{refresh_token}",
    "refresh_token_expires_in": 86400,
    "access_token": "{access_token}",
    "expires_in": 43200,
    "created_at": "2021-09-01T20:46:03.1354057+03:00"
}

Failed Response (Username or password incorrect)

Status Code : 401 Unauthorized

{
    "Message": "Username or password is wrong",
    "ErrorCode": "UsernameOrPasswordIsWrong",
    "StatusCode": 401
}

Failed Response (X-Ertis-Alias Header Missing)

Status Code : 400 Bad Request

{
    "message": "Membership id should be added in headers with 'X-Ertis-Alias' key.",
    "errorCode": "XErtisAliasMissing",
    "statusCode": 400
}


Me / Whoami


Request Model

curl --location --request GET '{{base_url}}/api/v1/me' \
--header 'Authorization: Bearer {{access_token}}'

or

curl --location --request GET '{{base_url}}/api/v1/whoami' \
--header 'Authorization: Bearer {{access_token}}'

Successful Response

Status Code : 200 OK

{
    "_id": "{{id}}",
    "firstname": "{{first_name}}",
    "lastname": "{{last_name}}",
    "username": "{{username}}",
    "email_address": "{{email}}",
    "role": "{{role}}",
    "permissions": [],
    "forbidden": [],
    "sys": {
        "created_at": "2021-06-03T20:29:22.545+03:00",
        "created_by": "{{created_by}}",
        "modified_at": "2021-09-01T18:31:57.932+03:00",
        "modified_by": "{{modified_by}}",
    },
    "membership_id": "{{membership_id}}"
}

Failed Response (Authorization Header Missing)

Status Code : 400 Bad Request

{
    "Message": "Authorization header missing or empty",
    "ErrorCode": "AuthorizationHeaderMissing",
    "StatusCode": 400
}

Failed Response (Ambiguous or unsupported token type)

Status Code : 400 Bad Request

{
   "Message": "Token type not supported. Token type must be one of Bearer or Basic",
   "ErrorCode": "TokenTypeNotSupported",
   "StatusCode": 400
}

Failed Response (Invalid token)

Status Code : 401 Unauthorized

{
   "Message": "Provided token is invalid",
   "ErrorCode": "InvalidToken",
   "StatusCode": 401
}

Failed Response (Expired token)

Status Code : 401 Unauthorized

{
   "Message": "Provided token was expired",
   "ErrorCode": "TokenWasExpired",
   "StatusCode": 401
}

Failed Response (Revoked token)

Status Code : 401 Unauthorized

{
   "Message": "Provided token was revoked",
   "ErrorCode": "TokenWasRevoked",
   "StatusCode": 401
}


Verify Token


Request Model

curl --location --request GET '{{base_url}}/api/v1/verify-token' \
--header 'Authorization: Bearer {{access_token}}'

or

curl --location --request POST '{{base_url}}/api/v1/verify-token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "token": "Bearer {{access_token}}"
}'

Successful Response

Status Code : 200 OK

{
    "verified": true,
    "token": "{{access_token}}",
    "token_kind": "access_token",
    "remaining_time": {{remaining_time_seconds}}
}


Refresh Token


Request Model

curl --location --request GET '{{base_url}}/api/v1/refresh-token' \
--header 'Authorization: Bearer {{refresh_token}}'

or

curl --location --request POST '{{base_url}}/api/v1/refresh-token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "token": "Bearer {{refresh_token}}"
}'

  If you want to revoke the current token besides the token refresh, add "?revoke=true" to the query string  


Successful Response

Status Code : 201 Created

{
    "token_type": "bearer",
    "refresh_token": "{refresh_token}",
    "refresh_token_expires_in": 86400,
    "access_token": "{{access_token}}",
    "expires_in": 43200,
    "created_at": "2021-09-01T20:46:03.1354057+03:00"
}

Failed Response (Expired refresh token)

Status Code : 401 Unauthorized

{
    "Message": "Provided refresh token was expired",
    "ErrorCode": "RefreshTokenWasExpired",
    "StatusCode": 401
}


Logout / Revoke Token


Request Model

curl --location --request GET '{{base_url}}/api/v1/revoke-token' \
--header 'Authorization: Bearer {{access_token}}'

or

curl --location --request POST '{{base_url}}/api/v1/revoke-token' \
--header 'Content-Type: application/json' \
--data-raw '{
    "token": "Bearer {{access_token}}"
}'

  If you want to log out of all sessions, add "?logout-all=true" to the query string. This operation will be signed-out of all sessions for the owner of the token on all devices.  


Successful Response

Status Code : 204 No Content


Failed Response (Invalid or already revoked token)

Status Code : 401 Unauthorized



Social Media Providers

ErtisAuth allows their customers to sign-up by using their email address and a password to create what's called a local account. Or, they can sign-up and sign in by using their Google, Facebook, or Microsoft accounts as their identity provider. By serving as the central authentication authority for your web applications, mobile apps, and APIs, ErtisAuth enables you to build a single sign-on (SSO) solution for them all. In addition to that, your customers can select sign in with their personal social media accounts. When users select social media login, they're redirected to a sign-in page hosted by provider. After the login process, ErtisAuth takes over the session and user management and resumes the transactions for you.

  In order to use social media providers, the necessary settings must be applied on the providers API and the provider must be activated. For details on the subject, see the providers section in the documentation.  

Login with Facebook

Request Model

curl --location --request POST '{{base_url}}/api/v1/oauth/facebook/login' \
--header 'X-Ertis-Alias: {{membership_id}}' \
--header 'X-IpAddress: {{client_ip}}' \
--header 'X-UserAgent: {{user_agent}}' \
--header 'Content-Type: application/json' \
  --data-raw '{
    "user": {{facebookUserPayload}},
    "appId": "{{facebookAppId}}"
}'

Facebook User Model

{
    id: string
    userID: string
    accessToken: string
    name?: string
    email?: string
    picture?: | {
        data: {
            height?: number
            is_silhouette?: boolean
            url?: string
            width?: number
        };
    }
}


Login with Google

Request Model

curl --location --request POST '{{base_url}}/api/v1/oauth/google/login' \
--header 'X-Ertis-Alias: {{membership_id}}' \
--header 'X-IpAddress: {{client_ip}}' \
--header 'X-UserAgent: {{user_agent}}' \
--header 'Content-Type: application/json' \
  --data-raw '{
    "token": {{googleCredentialsPayload}},
    "clientId": "{{googleClientId}}"
}'

Google Credentials Model

{
    idToken: string
    clientId: string
}


Login with Microsoft

Request Model

curl --location --request POST '{{base_url}}/api/v1/oauth/microsoft/login' \
--header 'X-Ertis-Alias: {{membership_id}}' \
--header 'X-IpAddress: {{client_ip}}' \
--header 'X-UserAgent: {{user_agent}}' \
--header 'Content-Type: application/json' \
  --data-raw '{
    "token": {{microsoftCredentialsPayload}},
    "clientId": "{{microsoftClientId}}"
}'

Microsoft Credentials Model

{
    authority: string
    uniqueId: string
    tenantId: string
    scopes: string[]
    account: {
        homeAccountId: string
        environment: string
        tenantId: string
        username: string
        localAccountId: string
        name?: string
        idToken?: string
        idTokenClaims?: {
            aud?: string
            iss?: string
            iat?: number
            nbf?: number
            oid?: string
            sub?: string
            tid?: string
            ver?: string
            upn?: string
            preferred_username?: string
            login_hint?: string
            emails?: string[]
            name?: string
            nonce?: string
            exp?: number
            home_oid?: string
            sid?: string
            cloud_instance_host_name?: string
            cnf?: {
                kid: string
            }
            x5c_ca?: string[]
            ts?: number
            at?: string
            u?: string
            p?: string
            m?: string
            roles?: string[]
            amr?: string[]
            idp?: string
            auth_time?: number
        }
        nativeAccountId?: string
    }
    idToken: string
    idTokenClaims: object
    accessToken: string
    fromCache: boolean
    expiresOn: Date
    tokenType: string
    correlationId: string
    requestId?: string
    extExpiresOn?: Date
    state?: string
    familyId?: string
    cloudGraphHostName?: string
    msGraphHost?: string
    code?: string
    fromNativeBroker?: boolean
}