{"id":44685040,"url":"https://github.com/karantin2020/jwtis","last_synced_at":"2026-02-15T05:34:02.761Z","repository":{"id":57481148,"uuid":"164325445","full_name":"karantin2020/jwtis","owner":"karantin2020","description":"JWTIS - JWT issuer server","archived":false,"fork":false,"pushed_at":"2020-08-12T17:38:43.000Z","size":18641,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-13T17:43:36.064Z","etag":null,"topics":["automatic","issuer","jose","jwk","jwt","server"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/karantin2020.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-06T16:34:47.000Z","updated_at":"2020-04-11T09:42:32.000Z","dependencies_parsed_at":"2022-09-26T17:50:39.863Z","dependency_job_id":null,"html_url":"https://github.com/karantin2020/jwtis","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/karantin2020/jwtis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karantin2020%2Fjwtis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karantin2020%2Fjwtis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karantin2020%2Fjwtis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karantin2020%2Fjwtis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karantin2020","download_url":"https://codeload.github.com/karantin2020/jwtis/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karantin2020%2Fjwtis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29470653,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T05:26:30.465Z","status":"ssl_error","status_checked_at":"2026-02-15T05:26:21.858Z","response_time":118,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automatic","issuer","jose","jwk","jwt","server"],"created_at":"2026-02-15T05:34:02.157Z","updated_at":"2026-02-15T05:34:02.756Z","avatar_url":"https://github.com/karantin2020.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"## JWTIS - JWT issuer server\n\n[![GoDoc](https://godoc.org/github.com/karantin2020/jwtis?status.svg)](https://godoc.org/github.com/karantin2020/jwtis)\n\nStand alone JWT issuer server. Just creates and renews JSON Web Tokens.\n\nUsed `gopkg.in/square/go-jose.v2` library.  \n**NOT** github.com/dgrijalva/jwt-go.  \nBut produced JSON Web Tokens are standard and may be verified and decrypted with any other library.  \nClient server (app) may use `github.com/dgrijalva/jwt-go` to verify tokens.\n\n#### Installation\n\nTo install JWTIS, you need to install Go and set your Go workspace first.\n\n1. Download and install it:\n\n```sh\n$ go get -u -d github.com/karantin2020/jwtis/cmd\n$ go install -o jwtis github.com/karantin2020/jwtis/cmd\n```\n\n2. Import as library:\n\n```go\nimport \"github.com/karantin2020/jwtis\"\n```\n\n#### Server configuration\n\n```sh\n./jwtis -h\n\nUsage: jwtis [OPTIONS]\n\nJWT issuer server. Provides trusted JWT tokens\n\nSource https://github.com/karantin2020/jwtis\n\nOptions:\n  -V, --version      Show the version and exit\n  -l, --listen       ip:port to listen to (env $JWTIS_ADDRESS) (default \"127.0.0.1:4343\")\n      --tls          Use tls connection [not implemented yet] (env $JWTIS_TLS)\n      --sigAlg       Default algorithn to be used for sign. Possible values are: ES256 ES384 ES512 EdDSA RS256 RS384 RS512 PS256 PS384 PS512 (env $JWTIS_SIG_ALG) (default \"ES256\")\n      --sigBits      Default key size in bits for sign key. Supported elliptic bit lengths are 256, 384, 521 (env $JWTIS_SIG_BITS) (default 256)\n      --encAlg       Default algorithn to be used for encrypt. Possible values are RSA1_5 RSA-OAEP RSA-OAEP-256 ECDH-ES ECDH-ES+A128KW ECDH-ES+A192KW ECDH-ES+A256KW (env $JWTIS_ENC_ALG) (default \"ECDH-ES+A256KW\")\n      --encBits      Default key size in bits for encrypt. Supported elliptic bit lengths are 256, 384, 521 (env $JWTIS_ENC_BITS) (default 256)\n      --contEnc      Default content encryption. Possible values are A128GCM, A192GCM, A256GCM (env $JWTIS_CONT_ENC) (default \"A256GCM\")\n  -e, --expiry       Default keys time to live, expiration time [Duration string] (env $JWTIS_EXPIRY) (default \"4320h\")\n  -a, --authTTL      Default auth JWT token time to live, expiration time [Duration string] (env $JWTIS_AUTH_TTL) (default \"72h\")\n  -r, --refreshTTL   Default refresh JWT token time to live, expiration time [Duration string] (env $JWTIS_REFRESH_TTL) (default \"720h\")\n  -n, --name         Name of this service (env $JWTIS_NAME) (default \"JWTIS\")\n  -p, --pswd         Storage password. App generates password with db creation. Later user must provide a password to access the database (env $JWTIS_PSWD)\n  -d, --dbPath       Path to store keys db (env $JWTIS_DB_PATH) (default \"./data/keys.db\")\n  -v, --verbose      Verbose. Show detailed logs (env $JWTIS_VERBOSE)\n```\n\n#### Start server\n\n```sh\n./jwtis\nWelcome. Started jwtis version v0.1.1\nCreated new bbolt database to store app's data\nGenerated new password: '?@P$mllo2H}W\u0026Y[EAFZiv4.LoCi3-8L?'\nPlease save the password safely, it's not recoverable\nCurrent configuration:\n  internalRepo.configs.listen:          127.0.0.1:4343\n  internalRepo.configs.tls:             false\n  internalRepo.configs.sigAlg:          ES256\n  internalRepo.configs.sigBits:         256\n  internalRepo.configs.encAlg:          ECDH-ES+A256KW\n  internalRepo.configs.encBits:         256\n  internalRepo.configs.contEnc:         A256GCM\n  internalRepo.configs.selfName:        JWTIS\n  internalRepo.configs.expiry:          4320h0m0s\n  internalRepo.configs.authTTL:         72h0m0s\n  internalRepo.configs.refreshTTL:      720h0m0s\n  confRepo.options.dbPath:              ./data/keys.db\njwtis works well\njwtis finished work\n\n./jwtis -p '?@P$mllo2H}W\u0026Y[EAFZiv4.LoCi3-8L?'\nWelcome. Started jwtis version v0.1.1\nFound existing bbolt database storing app's data\nUse user inserted password to bboltDB\nCurrent configuration:\n  internalRepo.configs.listen:          127.0.0.1:4343\n  internalRepo.configs.tls:             false\n  internalRepo.configs.sigAlg:          ES256\n  internalRepo.configs.sigBits:         256\n  internalRepo.configs.encAlg:          ECDH-ES+A256KW\n  internalRepo.configs.encBits:         256\n  internalRepo.configs.contEnc:         A256GCM\n  internalRepo.configs.selfName:        JWTIS\n  internalRepo.configs.expiry:          4320h0m0s\n  internalRepo.configs.authTTL:         72h0m0s\n  internalRepo.configs.refreshTTL:      720h0m0s\n  confRepo.options.dbPath:              ./data/keys.db\njwtis works well\n```\n\n#### When started first time JWTIS will:\n\n- generate new boltdb password\n  - You must save this password, it's not recoverable\n- create boltdb database file\n- start server with default or user provided configuration\n\n#### Terms\n\n- jwtis - is this server\n- client server (or app, business logic layer, domain logic layer) - the server which requests tokens from jwtis\n- web client (user) - the end consumer, client, user which requests client server\n- auth token and refresh token are described later in README\n\n#### What is it for:\n\n- automate sign and encrypt key creation, storing and revision\n- automate producing JWTs (no need to implement it yourself)\n- providing two tokens: short lived auth token and long lived refresh token\n- signed and encrypted refresh token provides more security\n- signed auth token may be verified with it's signature and with matching refresh token\n- client server fetches tokens' set for certain web client (user) and authenticates user with that tokens\n- client server (app) never encrypts anything\n- many client servers may use one JWTIS instance\n- all info on JWTIS is stored encrypted in embedded database\n\n#### Short-lived (minutes) JWT Auth Token\n\nThe short-lived jwt auth token allows the user to make stateless requests to protected api endpoints. It has an expiration time of 15 minutes by default and will be refreshed by the longer-lived refresh token.\n\n#### Longer-lived (hours/days) JWT Refresh Token\n\nThis longer-lived token will be used to update the auth tokens. These tokens have a 72 hour expiration time by default which will be updated each time an auth token is refreshed.  \nRefresh tokens are signed and encrypted  \nThese refresh tokens can be revoked by an authorized client\n\n#### JWTIS flow implementation\n\n- client server (business logic layer, domain logic layer) requests JWT\n- JWTIS generates tokens and sends them to client server\n- client server authenticates web client with this tokens as ussually\n\n#### Sign algorithms\n\n```\n  ES256 ES384 ES512 EdDSA RS256 RS384 RS512 PS256 PS384 PS512\n```\n\n#### Encrypt algorithms\n\n```\n  RSA1_5 RSA-OAEP RSA-OAEP-256 ECDH-ES ECDH-ES+A128KW ECDH-ES+A192KW ECDH-ES+A256KW\n```\n\n#### JWTIS http endpoints\n\n- /register/:kid\n  `- register new client server (app)`\n\n  - method\n\n  ```\n      POST\n  ```\n\n  - payload\n\n  ```go\n    // RegisterClientRequest sent to jwtis to register new client\n    type RegisterClientRequest struct {\n      Expiry Duration `json:\"expiry,omitempty\"` // keys ttl, optional\n\n      SigAlg  string `json:\"sig_alg,omitempty\"`  // default algorithn to be used for sign, optional\n      SigBits int    `json:\"sig_bits,omitempty\"` // default key size in bits for sign, optional\n      EncAlg  string `json:\"enc_alg,omitempty\"`  // default algorithn to be used for encrypt, optional\n      EncBits int    `json:\"enc_bits,omitempty\"` // default key size in bits for encrypt, optional\n\n      AuthTTL    Duration `json:\"auth_ttl,omitempty\"`    // default auth jwt ttl, optional\n      RefreshTTL Duration `json:\"refresh_ttl,omitempty\"` // default refresh jwt ttl, optional\n\n      // RefreshStrategy is used in RenewJWT to decide wheather to issue new refresh token\n      // with access token or not\n      // this option applies to all renewJWT requests\n      RefreshStrategy string `json:\"refresh_strategy,omitempty\"` // optional, values are: 'refreshBoth', 'refreshOnExpire', 'noRefresh' (default)\n    }\n  ```\n\n  - response\n\n  ```go\n    // RegisterClientResponse sent to client after it's registration\n    type RegisterClientResponse struct {\n      Kid         string          `json:\"kid,omitempty\"`          // Keys id to use\n      ClientToken string          `json:\"client_token,omitempty\"` // Client token given after registration [reserved]\n      PubSigKey   jose.JSONWebKey `json:\"pub_sig_key,omitempty\"`  // Public sign key to verify AccessTokens\n      PubEncKey   jose.JSONWebKey `json:\"pub_enc_key,omitempty\"`  // Public enc key to decrypt RefreshTokens\n      Expiry      jwt.NumericDate `json:\"expiry,omitempty\"`\n      Valid       bool            `json:\"valid,omitempty\"`\n    }\n  ```\n\n- /keys/:kid\n  `- fetch client server (app) public keys [TODO]`\n\n  - request for previously generated public keys for JWT\n  - request for new pub and priv JSONWebKey, not for jwt issuing\n  - and other functions\n  - requests send parameters in url queue or req body\n\n- /renew_keys\n  `- request new client server (app) keys [TODO]`\n\n  - method\n\n- /issue_token\n  `- request new token set for client server with kid`\n\n  - method\n\n  ```\n  POST\n  ```\n\n  - payload\n\n  ```go\n  // NewTokenRequest sent to jwtis to fetch new jwt\n  // ClientToken {string} - must be in header\n  type NewTokenRequest struct {\n    Kid                   string                 `json:\"kid\"` // Keys id to use\n    AuthTokenValidTime    time.Duration          `json:\"auth_token_valid_time,omitempty\"`\n    ResreshTokenValidTime time.Duration          `json:\"resresh_token_valid_time,omitempty\"`\n    Claims                map[string]interface{} `json:\"claims,omitempty\"` // Custom claims\n  }\n  ```\n\n  - response\n\n  ```go\n  // TokenResponse sent to client that requested tokens\n  type TokenResponse struct {\n    ID           string          `json:\"id\"`\n    AuthToken    string          `json:\"auth_token\"`    // Short lived auth token\n    RefreshToken string          `json:\"refresh_token\"` // Long lived refresh token\n    Expiry       jwt.NumericDate `json:\"expiry\"`\n  }\n  ```\n\n* /renew_token\n  `- renew auth token for client server based on refresh token.`\n  `Only if refresh token is valid. Otherwise need to request new token`\n\n  - method\n\n  ```\n  POST\n  ```\n\n  - payload\n\n  ```go\n    // RenewTokenRequest sent to jwtis to fetch new jwt\n    // ClientToken {string} - must be in header\n    type RenewTokenRequest struct {\n      Kid string `json:\"kid\"` // Keys id to use\n      // AccessTokenValidTime  Duration `json:\"access_token_valid_time,omitempty\"`\n      // RefreshTokenValidTime Duration `json:\"refresh_token_valid_time,omitempty\"`\n      RefreshToken string `json:\"refresh_token\"`\n      // RefreshStrategy is used in RenewJWT to decide wheather to issue new refresh token\n      // with access token or not\n      // this option applies only to a specific request\n      RefreshStrategy string `json:\"refresh_strategy,omitempty\"` // optional, values are: 'refreshBoth', 'refreshOnExpire', 'noRefresh' (default)\n    }\n  ```\n\n  - response\n\n  ```go\n    // TokenResponse sent to client that requested tokens\n    type TokenResponse struct {\n      ID           string          `json:\"id\"`\n      AccessToken  string          `json:\"access_token\"`  // Short lived auth token\n      RefreshToken string          `json:\"refresh_token\"` // Long lived refresh token\n      Expiry       jwt.NumericDate `json:\"expiry\"`\n    }\n  ```\n\nContributions are welcome\n\n#### For note: JWT Structure\n\n1. \"iss\" (Issuer) Claim\n\n   The \"iss\" (issuer) claim identifies the principal that issued the\n   JWT. The processing of this claim is generally application specific.\n   The \"iss\" value is a case-sensitive string containing a StringOrURI\n   value. Use of this claim is OPTIONAL.\n\n2. \"sub\" (Subject) Claim\n\n   The \"sub\" (subject) claim identifies the principal that is the\n   subject of the JWT. The claims in a JWT are normally statements\n   about the subject. The subject value MUST either be scoped to be\n   locally unique in the context of the issuer or be globally unique.\n   The processing of this claim is generally application specific. The\n   \"sub\" value is a case-sensitive string containing a StringOrURI\n   value. Use of this claim is OPTIONAL.\n\n3. \"aud\" (Audience) Claim\n\n   The \"aud\" (audience) claim identifies the recipients that the JWT is\n   intended for. Each principal intended to process the JWT MUST\n   identify itself with a value in the audience claim. If the principal\n   processing the claim does not identify itself with a value in the\n   \"aud\" claim when this claim is present, then the JWT MUST be\n   rejected. In the general case, the \"aud\" value is an array of case-\n   sensitive strings, each containing a StringOrURI value. In the\n   special case when the JWT has one audience, the \"aud\" value MAY be a\n   single case-sensitive string containing a StringOrURI value. The\n   interpretation of audience values is generally application specific.\n   Use of this claim is OPTIONAL.\n\n4. \"exp\" (Expiration Time) Claim\n\n   The \"exp\" (expiration time) claim identifies the expiration time on\n   or after which the JWT MUST NOT be accepted for processing. The\n   processing of the \"exp\" claim requires that the current date/time\n   MUST be before the expiration date/time listed in the \"exp\" claim.\n   Implementers MAY provide for some small leeway, usually no more than\n   a few minutes, to account for clock skew. Its value MUST be a number\n   containing a NumericDate value. Use of this claim is OPTIONAL.\n\n5. \"nbf\" (Not Before) Claim\n\n   The \"nbf\" (not before) claim identifies the time before which the JWT\n   MUST NOT be accepted for processing. The processing of the \"nbf\"\n   claim requires that the current date/time MUST be after or equal to\n   the not-before date/time listed in the \"nbf\" claim. Implementers MAY\n   provide for some small leeway, usually no more than a few minutes, to\n   account for clock skew. Its value MUST be a number containing a\n   NumericDate value. Use of this claim is OPTIONAL.\n\n6. \"iat\" (Issued At) Claim\n\n   The \"iat\" (issued at) claim identifies the time at which the JWT was\n   issued. This claim can be used to determine the age of the JWT. Its\n   value MUST be a number containing a NumericDate value. Use of this\n   claim is OPTIONAL.\n\n7. \"jti\" (JWT ID) Claim\n\n   The \"jti\" (JWT ID) claim provides a unique identifier for the JWT.\n   The identifier value MUST be assigned in a manner that ensures that\n   there is a negligible probability that the same value will be\n   accidentally assigned to a different data object; if the application\n   uses multiple issuers, collisions MUST be prevented among values\n   produced by different issuers as well. The \"jti\" claim can be used\n   to prevent the JWT from being replayed. The \"jti\" value is a case-\n   sensitive string. Use of this claim is OPTIONAL.\n\nSource is https://tools.ietf.org/html/rfc7519#section-4.1\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarantin2020%2Fjwtis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarantin2020%2Fjwtis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarantin2020%2Fjwtis/lists"}