Skip to content

Authentication Mechanism in NRF: What Is OAuth?

Note

Author: Wilson
Date: 2023/8/2

Abstract

Regarding the theme this time, I will briefly introduce OAuth. OAuth 2.0 defines four types of authorization flows. I choose the Client Credentials Flow to explain because the authentication mechanism in NRF is closely related to the Client Credentials Flow.

Next, I will explain how to apply the concept of the Client Credentials Flow to NRF and introduce Nnrf_AccessToken Service, because Nnrf_AccessToken Service is closely related to the Client Credentials Flow.

Finally, I will make a simple experiment of the authentication mechanism in NRF and share the environment settings and methods of operation.

OAuth

Before explaining the authentication mechanism in NRF, I will introduce OAuth. Regarding the OAuth flow, we can log in to the account through the platform before accessing an application. After logging in, we agree that an application can limitedly obtain the information of the user on the platform. The application can be LinkedIn, YouTube, etc. The platform can be Google, Facebook, etc.

The full English name of OAuth is Open standard Authorization. OAuth is an open standard, and it's used to deal with authorization-related behaviors. OAuth 2.0 defines four types of authorization flows. The four types of the authorization flows are:

  • Authorization Code
  • Implicit
  • Resource Owner Password Credentials
  • Client Credentials

This article explains the entire authorization of the Client Credentials Flow only, because the authentication mechanism in NRF adopts the Client Credentials.

If you're interested in how authorization mechanism works, please refer to this article for more details.

Client Credentials Flow



Figure 1. Client Credentials Flow

Referring to the Figure 1, the Client Credentials Flow is mainly composed of:

  • Client
  • Authorization Server
  • Resource Server

The entire authorization of the Client Credentials Flow can be devided into 3 steps:

  • First, the Client provdies Client ID, Client Secret Token, Scope, and Grant Type to the Authorization Server.
  • Second, the Authorization Server verifies the information provided by the Client. After the Authorization Server verifies the information, it signs with the private key and sends the Access Token to the Client.
  • Third, the Client obtains resources from the Resource Server with the Access Token.

In addition, the Client and the Authorization Server have their own Scope list. The Scope list records a series of the actions. The Client or the Authorization Server is permitted to do the actions for obtaining the user’s name, deleting posts, etc.

Below I will explain how to apply the Client Credentials Flow to NRF after talking about the Client Credentials Flow.

Client Credentials Flow in NRF

The Figure 2 and the Figure 3 originate from the Figure 13.4.1.1-1 and the Figure 13.4.1.1-2 of the TS 33.501.



Figure 2. NF Service Consumer Obtaining Access Token before NF Service Access

The entire flow in Figure 2 is the same as Step 1 and Step 2 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Authorization Server is played by the NRF.

First, the NF Service Consumer registers with NRF. Then the NF Service Consumer sends the Nnrf_AccessToken_Get Request to NRF. The Nnrf_AccessToken_Get Request includes:

  • Consumer NF Type
  • Expected NF Type
  • Expected NF Service Name
  • Client ID

The NF Type can be AMF, SMF, etc. , and the NF Service Name can be namf-comm, nsmf-pdusession, etc.

NRF verifies the information provided by the NF Service Consumer after it receives the Nnrf_AccessToken_Get Request. NRF generates an Access Token and uses the NRF private key to sign on the Access Token after the verification is successful.

Finally, NRF returns the Nnrf_AccessToken_Get Response to the NF Service Consumer. The NF Service Consumer stores the Access Token within the validity period after it gets the Access Token. The services provided by the NF Service Producer are in the Expected NF Service Name. The NF Service Consumer doesn’t need to verify again when it wants to use the services provided by the NF Service Producer.



Figure 3. NF Service Consumer Requesting Service Access with an Access Token

The entire flow in Figure 3 is the same as Step 3 in the Figure 1. The role of the Client is played by the NF Service Consumer, and the role of the Resource Server is played by the NF Service Producer.

First, the NF Service Consumer sends the NF Service Request to the NF Service Producer with the Access Token. Simply put, the NF Service Consumer wants to consume the service provided by the NF Service Producer.

The NF Service Producer uses the NRF public key to verify the signed Access Token after it receives the NF Service Request. If the verification is successful, the NF Service Producer will send the NF Service Response to the NF Service Consumer.

Now I will talk about the Nnrf_AccessToken Service after explaining how to apply the Client Credentials Flow to NRF.

Nnrf_AccessToken Service



Figure 4. Access Token Request

The Figure 4 originates from the Figure 5.4.2.2.1-1 of the TS 29.510.

First, the NF Service Consumer sends the POST /oauth2/token to NRF, and the data is stored in the AccessTokenReq. The attribute name, the data type, and the formulation rule of the AccessTokenReq are shown in the Table 1. The Table 1 originates from the Table 6.3.5.2.2-1 of the TS 29.510.



Table 1. Definition of Type AccessTokenReq

Definition of type AccessTokenReq:

  • grant_type: The value must be set to the client_credentials, and it is checked in the Snippet 1.
  • nfInstanceId: The value stores the ID of the NF Service Consumer.
  • targetNfInstanceId: The value stores the ID of the NF Service Producer.
  • nfType: The value stores the network function name of the NF Service Consumer. The network function name can be the AMF, SMF, etc.
  • targetNfType: The value stores the network function name of the NF Service Producer.
  • scope: It stores the services. The services can be the namf-comm, nsmf-pdusession, etc. When the NF Service Consumer requests the services. The services will be provided by the NF Service Producer.
  • requesterPlmn: It is mainly used in the roaming.
  • targetPlmn: It is mainly used in the roaming.

if reqGrantType != "client_credentials" {
    return &models.AccessTokenErr{
        Error: "unsupported_grant_type",
    }
}

Snippet 1. Grant Type Value Checking

NRF sends AccessTokenRsp to the NF Service Consumer in the Step 2a of the Figure 4. The attribute name, the data type, and the formulation rule of the AccessTokenRsp are shown in the Table 2. The Table 2 originates from the Table 6.3.5.2.3-1 of the TS 29.510.



Table 2. Definition of Type AccessTokenRsp

The AccessTokenRsp contains four attribute names. The four attribute names are:

  • access_token: It stores all the attribute names and values of the AccessTokenClaims in the Table 3. The Table 3 originates form the Table 6.3.5.2.4-1 of the TS 29.510.
  • token_type: It must be set to the Bearer and can be seen in the Snippet 2.
  • expires_in: It stores information related to the expiration date.
  • scope: The NF Service Consumer and the NF Service Producer have their own scope list. The scope in the AccessTokenRsp has a series of these services, and the NF Service Producer is permitted to consume these services.



Table 3. Definition of Type AccessTokenClaims

Definition of Type AccessTokenClaims:

  • iss: It is called issuer, and the content usually stores the ID of NRF.
  • sub: It is called subject, and the content stores the ID of the NF Service Consumer.
  • aud: It is called audience, and the content stores the ID of the NF Service Producer.
  • scope: The scope in the AccessTokenClaims has a series of these services, and the NF Service Consumer is authorized by the NF Service Producer and permitted to consume these services.
  • exp: It stores information related to the validity period.

func AccessTokenProcedure(request models.AccessTokenReq) (
    *models.AccessTokenRsp, *models.AccessTokenErr,
) {
    logger.AccTokenLog.Infoln("In AccessTokenProcedure")

    var expiration int32 = 1000
    scope := request.Scope
    tokenType := "Bearer"
    now := int32(time.Now().Unix())

    errResponse := AccessTokenScopeCheck(request)
    if errResponse != nil {
        return nil, errResponse
    }

    // Create AccessToken
    nrfCtx := nrf_context.GetSelf()
    accessTokenClaims := models.AccessTokenClaims{
        Iss:            nrfCtx.Nrf_NfInstanceID,    // NF instance id of the NRF
        Sub:            request.NfInstanceId,       // nfInstanceId of service consumer
        Aud:            request.TargetNfInstanceId, // nfInstanceId of service producer
        Scope:          request.Scope,              // TODO: the name of the NF services for which the
        Exp:            now + expiration,           // access_token is authorized for use
        StandardClaims: jwt.StandardClaims{},
    }
    accessTokenClaims.IssuedAt = int64(now)

    // Use NRF private key to sign AccessToken
    token := jwt.NewWithClaims(jwt.GetSigningMethod("RS512"), accessTokenClaims)
    accessToken, err := token.SignedString(nrfCtx.NrfPrivKey)
    if err != nil {
        logger.AccTokenLog.Warnln("Signed string error: ", err)
        return nil, &models.AccessTokenErr{
            Error: "invalid_request",
        }
    }

    response := &models.AccessTokenRsp{
        AccessToken: accessToken,
        TokenType:   tokenType,
        ExpiresIn:   expiration,
        Scope:       scope,
    }
    return response, nil
}

Snippet 2. AccessTokenProcedure Function

The Snippet 2 is the AccessTokenProcedure() function. The function is executed in NRF.

The function mainly processes:

  1. The NRF receives the AccessTokenReq sent by the NF Service Consumer.
  2. The function calls the AccessTokenScopeCheck() function. The AccessTokenScopeCheck() function checks whether the content of the attribute name in the AccessTokenReq complies with the requirements of the TS 29.510. If not, the AccessTokenProcedure() function immediately returns the AccessTokenErr to the NF Service Consumer.
  3. The function starts to create the Access Token. The Access Token is stored in the AccessTokenRsp. The AccessTokenRsp is sent back to the NF Service Consumer. The Iss in the AccessToken obtains its own ID in NRF. The Sub and Aud are obtained from the NfInstancedId and the TargetNfInstanceId in the AccessTokenReq respectively. The Scope is obtained from the scope in the AccessTokenReq. The expiration is set to the 1000 in the Snippet 2. Therefore, the value of the exp is the current time + 1000.
  4. After the Access Token is created, the function uses the NRF private key to sign on the Access Token. After signing, the function checks whether there is an error. If so, the function immediately sends the AccessTokenErr to the NF Service Consumer.
  5. The function puts the signed Access Token into the AccessTokenRsp. The value of the TokenType is set to the Bearer by the function. The function sets the ExprieIn and the Scope in the Snippet 2.

Finally, I make a simple experiment about the Access Token and share the environment setting and method of operation with you.

Experiment

The Table 4 is my environment setting. I provide the Table 4 for you. You can refer it.



Table 4. Environment

Remove the part of the tls and add the content of the cert, rootcert and oauth under sbi in the nrfcfg.yaml before implementing about the Access Token.

info:
  version: 1.0.2
  description: NRF initial local configuration

configuration:
  MongoDBName: free5gc # database name in MongoDB
  MongoDBUrl: mongodb://127.0.0.1:27017 # a valid URL of the mongodb
  sbi: # Service-based interface information
    scheme: http # the protocol for sbi (http or https)
    registerIPv4: 127.0.0.10 # IP used to serve NFs or register to another NRF
    bindingIPv4: 127.0.0.10  # IP used to bind the service
    port: 8000 # port used to bind the service
    cert:
      pem: cert/nrf.pem
      key: cert/nrf.key
    rootcert:
      pem: cert/nrf.pem
      key: cert/nrf.key
    oauth: true
  DefaultPlmnId:
    mcc: 208 # Mobile Country Code (3 digits string, digit: 0~9)
    mnc: 93 # Mobile Network Code (2 or 3 digits string, digit: 0~9)
  serviceNameList: # the SBI services provided by this NRF, refer to TS 29.510
    - nnrf-nfm # Nnrf_NFManagement service
    - nnrf-disc # Nnrf_NFDiscovery service

logger: # log output setting
  enable: true # true or false
  level: info # how detailed to output, value: trace, debug, info, warn, error, fatal, panic
  reportCaller: false # enable the caller report or not, value: true or false

nrfcfg.yaml

Find the http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531 in the NRF log, and you will get the 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The 8f7891b4-b127-4f59-9ec2-b5e6aade5531 is the nfInstanceID.

2023-08-02T20:07:43.300826205Z [INFO][NRF][NFM] Handle NFRegisterRequest
2023-08-02T20:07:43.308259291Z [INFO][NRF][NFM] urilist create
2023-08-02T20:07:43.311674255Z [INFO][NRF][NFM] Create NF Profile
2023-08-02T20:07:43.318192771Z [INFO][NRF][NFM] Location header:  http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531
2023-08-02T20:07:43.325073275Z [INFO][NRF][GIN] | 201 |       127.0.0.1 | PUT     | /nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531 |

Execute $ curl -X GET {apiRoot}/nnrf-nfm/v1/nf-instances/{nfInstanceID}, and you will obtain the detail information about the nfInstanceID. You can see the nfType of the nfInstanceID is NSSF, and the information about the nfInstanceID is used when you implement the Access Token.

ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X GET http://127.0.0.10:8000/nnrf-nfm/v1/nf-instances/8f7891b4-b127-4f59-9ec2-b5e6aade5531
{"ipv4Addresses":["127.0.0.31"],"nfInstanceId":"8f7891b4-b127-4f59-9ec2-b5e6aade5531","nfServices":[{"apiPrefix":"http://127.0.0.31:8000","ipEndPoints":[{"ipv4Address":"127.0.0.31","port":8000,"transport":"TCP"}],"nfServiceStatus":"REGISTERED","scheme":"http","serviceInstanceId":"0","serviceName":"nnssf-nsselection","versions":[{"apiFullVersion":"1.0.2","apiVersionInUri":"v1"}]},{"apiPrefix":"http://127.0.0.31:8000","ipEndPoints":[{"ipv4Address":"127.0.0.31","port":8000,"transport":"TCP"}],"nfServiceStatus":"REGISTERED","scheme":"http","serviceInstanceId":"1","serviceName":"nnssf-nssaiavailability","versions":[{"apiFullVersion":"1.0.2","apiVersionInUri":"v1"}]}],"nfStatus":"REGISTERED","nfType":"NSSF","plmnList":[{"mcc":"208","mnc":"93"}]}

Then you execute this command, see below.

$ curl -X POST -H "Content-Type: application/json" -d '{"nfInstanceId": {nfInstanceID}, "grant_type": "client_credentials", "nfType": {nfType}, "targetNfType": "UDR", "scope": "nudr-dr"}' {apiRoot}/oauth2/token

You will get the long symbols. The long symbols is that the Access Token is encrypted by the private key of NRF and stored in the AccessTokenRsp.

ubuntu@free5GC:~/free5gc/NFs/nrf$ curl -X POST -H "Content-Type: application/json" -d '{"nfInstanceId": "8f7891b4-b127-4f59-9ec2-b5e6aade5531", "grant_type": "client_credentials", "nfType": "NSSF", "targetNfType": "UDR", "scope": "nudr-dr"}' http://127.0.0.10:8000/oauth2/token
"eyJhY2Nlc3NfdG9rZW4iOiJleUpoYkdjaU9pSlNVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKcGMzTWlPaUlpTENKemRXSWlPaUk0WmpjNE9URmlOQzFpTVRJM0xUUm1OVGt0T1dWak1pMWlOV1UyWVdGa1pUVTFNekVpTENKaGRXUWlPaUlpTENKelkyOXdaU0k2SW01MVpISXRaSElpTENKbGVIQWlPakUyT1RFd01EZzBPRGdzSW1saGRDSTZNVFk1TVRBd056UTRPSDAuY3VHSkkwTndfV280S2lQbS1fZEZVdnVTQWM1WVEwMmRKYk5PTUhmMV9IOHdIZ2JKWFhUam9xU1Y2OTNYSmFKemkweGIxdC1DMW14TWhVZkZjbXpNMC1Nd2oxTXZYaWhyTTktdDFRUFItSFcxQlBlN0tHMUxBV3d5MEJfcXpIalltRlR6eGhONVlyNkpURDhBbkMxaFJFeEh4WHBjV1NqbV9vZnV0NVhfUFRFRkZtaHZrbmtVbU8waWFrTmdRWElRVTc1NnlvZ29ZTlFDRnJvSmRWamJMdnpFdkJLYTVFN0hQeXc3RkRDRHpTZU5WT2t2WTlobU11eldYZ3dOVmRIT3c1c2lNbmppbTlmTVZ0RTFxS1hjWDlScXlUdXlsWjM2ZlJ1QjdVZ2hkLU15Q19xd2VJRE41ZFdYOWZqdnA3VUNZZ01mVHhSLUI2M3d5OWFjQ183eThRIiwidG9rZW5fdHlwZSI6IkJlYXJlciIsImV4cGlyZXNfaW4iOjEwMDAsInNjb3BlIjoibnVkci1kciJ9"

NSSF sends the AccessTokenReq to NRF after you execute the above command. In the AccessTokenReq, the nfInstanceId is set to 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The grant_type is set to the client_credentials. The nfType is set to NSSF. The targetNfType is set to UDR. The scope is set to nudr-dr. The information is shown in the NRF log. The value of the targetNfInstanceId, requesterPlmn, and targetPlmn is empty because they are not set.

2023-08-02T20:18:08.127557565Z [INFO][NRF][Token] In AccessTokenProcedure
2023-08-02T20:18:08.127586736Z [INFO][NRF][Token] Access Token Request
2023-08-02T20:18:08.127611885Z [INFO][NRF][Token] Grant Type: client_credentials
2023-08-02T20:18:08.127637480Z [INFO][NRF][Token] NF Instance ID: 8f7891b4-b127-4f59-9ec2-b5e6aade5531
2023-08-02T20:18:08.127664415Z [INFO][NRF][Token] Target NF Instance ID:
2023-08-02T20:18:08.127689792Z [INFO][NRF][Token] NF Type: NSSF
2023-08-02T20:18:08.127712916Z [INFO][NRF][Token] Target NF Type: UDR
2023-08-02T20:18:08.127734827Z [INFO][NRF][Token] Scope: nudr-dr
2023-08-02T20:18:08.127758317Z [INFO][NRF][Token] Requester PLMN: <nil>
2023-08-02T20:18:08.127781052Z [INFO][NRF][Token] Target PLMN: <nil>

Next, you can see the Access Token in the NRF log. The value of the Sub is 8f7891b4-b127-4f59-9ec2-b5e6aade5531. The Sub represents NSSF, and NSSF belongs to the NF Service Consumer. The value of the Scope is the nudr-dr. The value of the Exp is 1691008488.

2023-08-02T20:18:08.134096785Z [INFO][NRF][Token] Access Token Claims
2023-08-02T20:18:08.138100978Z [INFO][NRF][Token] Iss:
2023-08-02T20:18:08.138185972Z [INFO][NRF][Token] Sub: 8f7891b4-b127-4f59-9ec2-b5e6aade5531
2023-08-02T20:18:08.138228925Z [INFO][NRF][Token] Aud:
2023-08-02T20:18:08.138264519Z [INFO][NRF][Token] Scope: nudr-dr
2023-08-02T20:18:08.138298628Z [INFO][NRF][Token] Exp: 1691008488

Next, you can see the AccessTokenRsp. You can see that the Access Token has become the long symbols. The value of the Token Type is set to the Bearer. The value of the ExpiresIn is set to 1000. The value of the Scope is set to nudr-dr.

2023-08-02T20:18:08.149587382Z [INFO][NRF][Token] Access Token Response
2023-08-02T20:18:08.150006665Z [INFO][NRF][Token] Access Token: eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiI4Zjc4OTFiNC1iMTI3LTRmNTktOWVjMi1iNWU2YWFkZTU1MzEiLCJhdWQiOiIiLCJzY29wZSI6Im51ZHItZHIiLCJleHAiOjE2OTEwMDg0ODgsImlhdCI6MTY5MTAwNzQ4OH0.cuGJI0Nw_Wo4KiPm-_dFUvuSAc5YQ02dJbNOMHf1_H8wHgbJXXTjoqSV693XJaJzi0xb1t-C1mxMhUfFcmzM0-Mwj1MvXihrM9-t1QPR-HW1BPe7KG1LAWwy0B_qzHjYmFTzxhN5Yr6JTD8AnC1hRExHxXpcWSjm_ofut5X_PTEFFmhvknkUmO0iakNgQXIQU756yogoYNQCFroJdVjbLvzEvBKa5E7HPyw7FDCDzSeNVOkvY9hmMuzWXgwNVdHOw5siMnjim9fMVtE1qKXcX9RqyTuylZ36fRuB7Ughd-MyC_qweIDN5dWX9fjvp7UCYgMfTxR-B63wy9acC_7y8Q
2023-08-02T20:18:08.150094277Z [INFO][NRF][Token] Token Type: Bearer
2023-08-02T20:18:08.150133189Z [INFO][NRF][Token] Expires In: 1000
2023-08-02T20:18:08.150167371Z [INFO][NRF][Token] Scope: nudr-dr

Finally, you can see 200. 200 means that AUSF sends the AccessTokenReq to NRF. NRF successfully sends to AUSF after verification.

2023-08-02T20:18:08.150302345Z [INFO][NRF][GIN] | 200 |       127.0.0.1 | POST    | /oauth2/token |

Reference

About

Hi, my name is Wilson. I am a master’s student. My main area of research is network slicing. In the future, I will introduce more information about 5G. Hope you enjoy it.

Note

If you are interested in supporting free5GC, we welcome your donation. Please visit this link for more details.