NexsterOrg / nexster

Runtime of all micro services for the Nexster social network.
https://community.nexster.xyz
Other
0 stars 0 forks source link

[Main] Identity Server building #10

Closed NamalSanjaya closed 1 year ago

NamalSanjaya commented 1 year ago

Identity Server need to have following capabilities

  1. User management system
  2. API clients Authenticate and Authorization system

This list can have more to add.

NamalSanjaya commented 1 year ago

API authenticate and Authorization

Each request comes to our servers need to have enough permission to serve by our servers. We need one place that have ability to check authenticity and required permission. Therefore all other servers need to rely on Identity server to verify its identity and whether it has required permission to access the resource.

Need to learn

NamalSanjaya commented 1 year ago

User management System

Concepts we need

  1. Authenticate system
  2. Authorization system
  3. Role based User management
  4. User groups

Authenticate System

  1. Password strength checking
  2. Throttling of login attempts
  3. Password hashing
NamalSanjaya commented 1 year ago

Example JWT-Headers

{
  "x5t": "YWY1NmRkZGI5MzE4ODBlZDRiMWI4ZWJlNjExZWViZjEzMmNmNDU3YQ",
  "kid": "MWQ5NWUwYWZiMmMzZTIzMzdmMzBhMWM4YjQyMjVhNWM4NjhkMGRmNzFlMGI3ZDlmYmQzNmEyMzhhYjBiNmZhYw_RS256",
  "alg": "RS256"
}

Example JWT-payload

{
  "sub": "6ded9f12-352d-4ad9-9cc0-c4803a8655bc",
  "aut": "APPLICATION_USER",
  "iss": "https://sts.choreo.dev:443/oauth2/token",
  "aud": [
    "ciwnWuwZfbcdzBUcnkhKvi_mcBUa",
    "https://sts.preview.choreo.dev:443/oauth2/token",
    "https://apim.preview.choreo.dev:443/oauth2/token",
    "https://sts.choreo.dev:443/oauth2/token"
  ],
  "nbf": 1685853490,
  "azp": "ciwnWuwZfbcdzBUcnkhKvi_mcBUa",
  "scope": "apim:admin apim:api_generate_key apim:api_manage apim:api_publish apim:api_settings apim:api_view apim:dcr:app_manage apim:document_manage apim:environment_manage apim:publisher_settings apim:subscribe apim:subscription_manage apim:subscription_view apim:tier_manage apim:tier_view choreo:component_manage choreo:deployment_manage choreo:dev_env_manage choreo:log_view_non_prod choreo:log_view_prod choreo:non_prod_env_manage choreo:prod_env_manage choreo:project_manage environments:view_dev environments:view_prod urn:choreosystem:choreodevopsportalapi:component_manage urn:choreosystem:choreodevopsportalapi:deployment_manage urn:choreosystem:choreodevopsportalapi:deployment_view urn:choreosystem:componentsmanagement:component_config_view urn:choreosystem:componentsmanagement:component_create urn:choreosystem:componentsmanagement:component_file_view urn:choreosystem:componentsmanagement:component_init_view urn:choreosystem:componentsmanagement:component_logs_view urn:choreosystem:componentsmanagement:component_manage urn:choreosystem:componentsmanagement:component_trigger urn:choreosystem:configmanagement:config_create urn:choreosystem:configmanagement:config_delete urn:choreosystem:configmanagement:config_manage urn:choreosystem:configmanagement:config_view urn:choreosystem:configmanagement:global_config_create urn:choreosystem:configmanagement:global_config_delete urn:choreosystem:configmanagement:global_config_manage urn:choreosystem:configmanagement:global_config_update urn:choreosystem:configmanagement:global_config_view urn:choreosystem:customdomainapi:custom_domain_create urn:choreosystem:customdomainapi:custom_domain_delete urn:choreosystem:customdomainapi:custom_domain_manage urn:choreosystem:customdomainapi:custom_domain_update urn:choreosystem:customdomainapi:custom_domain_view urn:choreosystem:onpremkeymanagement:on_prem_key_create urn:choreosystem:onpremkeymanagement:on_prem_key_delete urn:choreosystem:onpremkeymanagement:on_prem_key_manage urn:choreosystem:onpremkeymanagement:on_prem_key_update urn:choreosystem:onpremkeymanagement:on_prem_key_view urn:choreosystem:organizationmanagement:enterprise_login_config_manage urn:choreosystem:organizationmanagement:enterprise_login_config_view urn:choreosystem:organizationmanagement:self_signup_approval_update urn:choreosystem:organizationmanagement:self_signup_approval_view urn:choreosystem:organizationmanagement:self_signup_config_update urn:choreosystem:organizationmanagement:self_signup_config_view urn:choreosystem:organizationmanagement:self_signup_manage urn:choreosystem:organizationmanagement:theme_create urn:choreosystem:organizationmanagement:theme_delete urn:choreosystem:organizationmanagement:theme_deploy urn:choreosystem:organizationmanagement:theme_manage urn:choreosystem:organizationmanagement:theme_view urn:choreosystem:usersmanagement:invitation_delete urn:choreosystem:usersmanagement:invitation_manage urn:choreosystem:usersmanagement:invitation_send urn:choreosystem:usersmanagement:invitation_view urn:choreosystem:usersmanagement:permission_view urn:choreosystem:usersmanagement:role_create urn:choreosystem:usersmanagement:role_delete urn:choreosystem:usersmanagement:role_manage urn:choreosystem:usersmanagement:role_mapping_create urn:choreosystem:usersmanagement:role_mapping_delete urn:choreosystem:usersmanagement:role_mapping_manage urn:choreosystem:usersmanagement:role_mapping_update urn:choreosystem:usersmanagement:role_mapping_view urn:choreosystem:usersmanagement:role_update urn:choreosystem:usersmanagement:role_view urn:choreosystem:usersmanagement:user_delete urn:choreosystem:usersmanagement:user_manage urn:choreosystem:usersmanagement:user_update urn:choreosystem:usersmanagement:user_view",
  "organization": {
    "handle": "namalbcsnv",
    "uuid": "c1b8ad67-c553-4253-8095-13f4467d3f4a"
  },
  "organizations": [
    "c1b8ad67-c553-4253-8095-13f4467d3f4a"
  ],
  "exp": 1685857090,
  "idp_claims": {
    "aut": "APPLICATION_USER",
    "authenticated_idp": "Google",
    "name": "Namal Sanjaya",
    "given_name": "Namal",
    "family_name": "Sanjaya",
    "email": "namalsanjaya23@gmail.com"
  },
  "iat": 1685853490,
  "jti": "7d825bbf-ed93-4d27-8b28-c4245629e40b"
}

We are sign JWT token using our private key(we have digital signature). Therefore other only can see this read this. they can't modify the content. Check more advatanges of using JWT token as an access token.

NamalSanjaya commented 1 year ago

I decide to use multi-model database which is arango db.

NamalSanjaya commented 1 year ago

JWT Registered claims

NamalSanjaya commented 1 year ago

JWT Payload structure (Not completed)

{
  "iss" : "https://mora.nexster.com/auth",
 "aud" : [
     "https://mora.nexster.com/auth", "https://mora.nexster.com/timeline"
 ] 
"sub" : "uuid of user",
"exp" : "194783291",
"username" : "Namal Sanjaya",
"img_url" : "https://api.profimage.com/users/34"
}

https://golang-jwt.github.io/jwt/

NamalSanjaya commented 1 year ago

Create JWT , Parse and Validate

package main

import (
    "fmt"
    "log"
    "os"
    "time"

    jwt "github.com/golang-jwt/jwt/v5"
)

func main() {
    stTime := time.Now()
    s := genJwt()

    fmt.Println(s)
    fmt.Println("---- End JWT ----")

    decodeJwt(s)

    fmt.Println("--done--, Ex: ", time.Now().Sub(stTime))
}

func genJwt() string {
    privateKey, err := os.ReadFile("private_key_pkcs8.pem")
    if err != nil {
        log.Fatal(err)
    }

    key, err := jwt.ParseECPrivateKeyFromPEM(privateKey)
    if err != nil {
        log.Fatal(err)
    }

    t := jwt.NewWithClaims(jwt.SigningMethodES256,
        jwt.MapClaims{
            "iss": "my-auth-server",
            "sub": "john",
            "foo": 2,
        })
    s, err := t.SignedString(key)
    if err != nil {
        log.Fatal(err)
    }
    return s
}

func decodeJwt(tokenString string) {

    key, err := os.ReadFile("public_key.pem")
    if err != nil {
        log.Fatal("Error file open: ", err)
    }

    publicKey, err := jwt.ParseECPublicKeyFromPEM(key)
    if err != nil {
        log.Fatal("Error ParseECPublic open: ", err)
    }

    token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
        return publicKey, nil // In this example, we use a constant public key
    })
    if err != nil {
        log.Fatal("Error parsing token:", err)
    }

    // Verify the token's signature
    if !token.Valid {
        log.Fatal("Invalid token signature")
    }

    // Access the claims contained within the token's payload
    claims, ok := token.Claims.(jwt.MapClaims)
    if !ok {
        log.Fatal("Invalid token claims")
    }

    // Access individual claim values
    issuer := claims["iss"].(string)
    subject := claims["sub"].(string)
    foo := int(claims["foo"].(float64)) // Cast to appropriate types

    // Print the decoded claims
    fmt.Println("Issuer:", issuer)
    fmt.Println("Subject:", subject)
    fmt.Println("Foo:", foo)

}
NamalSanjaya commented 1 year ago

Store JWT In browser

Cookie

Set-Cookie: jwt=OUR_TOKEN_CONTENT; secure; httpOnly; sameSite=Lax;

https://tkacz.pro/how-to-securely-store-jwt-tokens/#:~:text=Use%20cookies%20to%20store%20JWT,manually%20on%20frontend%20code%20anymore.

NamalSanjaya commented 1 year ago

TODO

NamalSanjaya commented 1 year ago

JWT validation in Nginx

https://mostafa-asg.github.io/post/nginx-authentication-with-jwt/ https://github.com/TeslaGov/ngx-http-auth-jwt-module

I have 2 architectures in my head

  1. Pass-through signature and algo validation at API Gateway and claim validation at respective micro service
  2. All Validations at respective micro service I have to follow this path if Nginx open source version can't do JWT validation itself.

We Go with 2nd option since I am unable to figure out a way to do JWT validation in Nginx open source. (in docker conainer it is possible I think. But we are not going in this path)

NamalSanjaya commented 1 year ago

Concerns

I have chosen cookie to store Jwt token. Browser won't automatically add token to API fetch request. Therefore, we have to remove httpOnly cookie attribute which is there to avoid XSS attacks. Now we are vularable to XSS attacks.

NamalSanjaya commented 1 year ago

JWT validation at React Server

NamalSanjaya commented 1 year ago

image

This is the current architecture.

Important Nots

  1. I could not figure out a way to do JWT token validation at NGINX. I could direct very request to another auth server and let the auth server to do the JWT validation, but it can create a performance bottleneck. There fore, I have to do JWT validation at each server. Not public Key is spread across multiple places.

  2. In future, we need to figure out a better way to that.

NamalSanjaya commented 1 year ago

Store user data at browser

Use localStorage to store user information Store user info

// Create the JavaScript object
const userData = {
    gender: "male",
    birthday: "2002-03-14",
    faculty: "engineering",
   userid: "482191"
};

// Store the JSON string in localStorage under a key (e.g., "user_data")
localStorage.setItem("user_data", JSON.stringify(userData));

Retrieve user info

// Retrieve the JSON string from localStorage
const jsonString = localStorage.getItem("user_data");

// Parse the JSON string back into a JavaScript object
const userData = JSON.parse(jsonString);

console.log(userData); // This will output the JavaScript object