Can I use a globally unique userid for 'sub' claim in OIDC ID Token? - jwt

I'm having hard time understanding OIDC that I'm asking here.
[Current Understanding]
ID Token (Based on JWT)
[REQUIRED]
iss (Issuer) : OPurl
sub (Subject Identifier) : unique identifier
aud (Audience) : Unique Client ID which OP provides beforehand
exp (Expires at) : When token expires
iat (Issued at) : When token is issued
[OPTIONAL]
nonce : string value used to associate a client session with ID token (REQ for Implicit Flow)
preferred_username : Shorthand name by which the End-User wishes to be referred to at the RP (The RP MUST NOT rely upon this value being unique)
Sample Token
{"access_token":"SlAV32hkKG","token_type":"bearer","expires_in":3600,"id_token":"eyJ0...","refresh_token":"8xLOxBtZp8"}
Authorization Code Flow (/authorize GET => /token POST) : contains refresh_token and is in JSON form
Implicit Flow (/authorize GET) : does not contain refresh_token and is responsed in fragment mode
Sample ID Token
Header (Base64 Decoded) : {"typ":"JWT","alg":"RS256","kid":"sdfikhRETlknsdfollksdf324lhk"}
Payload (Base64 Decoded) : {"iss":"OPurl","aud":"ClientID","sub":"1234567890","exp":"1665666710","iat":"1665666790"}
Signature : ggW8hZ...zqg
[Question]
In OIDC Core Spec, sub(subject identifier) is a "locally unique and never reassigned identifier within the Issuer for the End-User, which is intended to be consumed by the Client".
In JWT Spec, it can either be locally unique in the context of the issuer or be globally unique.
Here I have a globally unique User ID. (Let's say 1234567890)
User uses this ID for client A, B, C... everywhere.
No others can use this ID.
Can sub be that ID itself? ("sub":"1234567890")
Or Should sub be like a mix of a random string with the id and preferred_username should be the ID itself? (Keycloak for example, returns the token like {"sub":"f:636436-348762gyu-234786234:1234567890", "preferred_username":1234567890})
I'm not really sure what it means to be "never reassigned identifier within the Issuer for the End-User"...
Any help would be appreciated.
Please let me know if my current understanding is wrong!

I am going to answer with the assumption you are the developer of a JWT producer.
Based on your comments you may also be the developer of the JWT consumer, which makes me wonder why you are choosing OIDC/JWT for this single identity flow. Either way I will respond with context of producer where the consumers are multiple identities authenticating with you, an identity provider, and you are simply coding the OIDC as an JWT producer.
Here I have a globally unique User ID. (Let's say 1234567890)
This is not appropriate if:
a) this user input of any kind (they register their own username)
b) the user may edit (or request an edit) to the value, e.g. an email address or user handle as a username
c) the numeric example it taken literally, the identifier should not be sequential or attackers can enumerate them easily.
It is common the aud and sub are kept associated in server persistent state, and later the JWK identifier (kid) will be set from the key alias (aud or sub for consistency and simplicity) in the store.
Therefore it is quite important to make the sub immutable, server generated, and this will help you to never orphan a key that would cause significant issues in practice.

It means that the subject identifier is a value that should never ever change.
It should be a unique value within your system.
Unlike preferred_username or email or name.

Related

What is a JWT Principal?

RFC 7519 (https://datatracker.ietf.org/doc/html/rfc7519)
mentions a principal but doesn't define it.
What is a JWT Principal?
From Wikipedia:
A principal in computer security is an entity that can be authenticated by a computer system or network.
Let's consider an example where we're using JWT for user's authentication, then e.g. in the Subject Claim's definition from the RFC 7519:
The "sub" (subject) claim identifies the principal that is the subject of the JWT. The claims in a JWT are normally statements about the subject. The subject value MUST either be scoped to be locally unique in the context of the issuer or be globally unique. The processing of this claim is generally application specific. The "sub" value is a case-sensitive string containing a StringOrURI value. Use of this claim is OPTIONAL.
, principal is a specific user for whom a specific token was issued, and "sub" claim is some id of this user.

How to read token value having it's accessor

When working with Hashicorp Vault one can see token details with
vault token lookup --accessor secret
but is it possible to actually see this token's value ?
No, you cannot. This is for security reason. Otherwise, you will not be able to create a new (child) token and share it with someone, cause in this case lookup will be able to reveal your (parent) token, that is not acceptable.
In general, the output for lookup command contains id part. This is the token value. For lookup command with --accessor flag id is always n/a in response.

Why is 'id' called 'sub' in keycloak?

Im looking at the new Keycloak Beta 4 API. When i get the users account information, what is referred to as 'id' in the web ui comes back as 'sub' in the account object.
{ sub: '25a37fd0-d10e-40ca-af6c-821f20e01be8',
name: 'Barrack Obama',
preferred_username: 'obama#whitehouse.gov',
given_name: 'Barrack',
family_name: 'Obama',
email: 'obama#whitehouse.gov' }
What is 'sub' and is this a safe uuid to map database objects to?
As per the keycloak documentation
Anatomy of Action Token
Action token is a standard Json Web Token signed with active realm key where the payload contains several fields:
typ - Identification of the action (e.g. verify-email)
iat and exp - Times of token validity
sub - ID of the user
azp - Client name
iss - Issuer - URL of the issuing realm
aud - Audience - list containing URL of the issuing realm
asid - ID of the authentication session (optional)
nonce - Random nonce to guarantee uniqueness of use if the operation can only be executed once (optional)
Please refer the following link https://www.keycloak.org/docs/latest/server_development/index.html#_action_token_anatomy
Reason may be they want to retain the uniqueness in the name.
In addition to the previous answer, inside JWT tokens, sub refers to subject. The reason is that those tokens can be used in various cases, including authorization. That means that id sometimes might not be "the unique identifier" but might be anything, including repeatable destinations. Basically, a naming convention JWT follows, regardless of Keycloak.

How Does The Server Know If A Bearer Token Is Valid Without Storing It On Disk Or Memory

So I just implemented token based authentication in a Web API app using OWIN and I was able to understand the concept of how it all works (well on the surface at least).
What I couldn't understand is how the server validates the generated bearer token without storing it on the disk or memory. I mean sure the expiration date is probably encrypted in the token itself, but that only applies if it is already expired. So how does the server do it (on a high level)?
Update:
Okay i can see that the claims are stored in the token.So at some level the server is still checking that with the db during authentication correct? Otherwise let's assume that i'm the server and I was able to decrypt the token to this object:
{
"iss": "thesite.com",
"exp": 1300819380,
"name": "Chris Sevilleja",
"admin": true
}
So the question now is does the fact that I (the server) was able to decrypt the token into key value pairs (checking for the presence of specific keys like 'iss', 'exp' and checking for values like the 'admin' key must be true) means that I will authorize the web request?
JWT token is made up with three parts separated by dot(.).
First part is Header.
Second part is Payload
Third Part is Signature (say s0)
JWT Format
Signature is created using Header and Payload.
When server receives JWT token it creates temporary signature (say s1) from incoming header and payload.
If s0 and s1 signatures are same then token is valid.
Also token contains claims which are used to validate token. e.g exp claim contains unix epoch time after which token is considered as invalid.
The token is encoded with the JWT format (JSON Web token). This is well described in the standard (https://www.rfc-editor.org/rfc/rfc7519) and you will see that the token contains a certain number of claims, among which the expiration date (exp).

restful api .. session security

assume an ordering application, user "Ben" would be able to list a specific order by issuing
/order/1
now .. before doing that i've authenticated "Ben" (username/password auth) and sent the username as a cookie (signed with a sha1 checksum).
on each http request i receive the cookie that tells me "Bent" is still authenticated, but who can stop him from issuing
/order/23
where order with id=23 does not belong to "Ben".
so i guess i should write some logic to make sure that order 23 actually belongs to "Ben" ... is that a best practice or pattern for this kind of situation ?
should i use a separate "functional primary key", instead of a serial primary key id ?
I don't see any reasonable natural primary key for order. To make it less discoverable you could use UUID (pretty small chance to accidentally find /orders/4886ed80-dd71-11e0-9572-0800200c9a66 )...
BUT it would be security by obscurity. Even if it's impossible for me to guess the UUID of your order, I can sniff your traffic and, if the security is only provided through obscure URLs, I will be able to do whatever I want with the Order resource.
That should make it clear that you cannot skip authentication in such case.