Skip to main content

OAuth 2.0 Authorization Code Grant

The Authorization Code Grant requests an authorization code that can be exchanged for an ID token and access token. Tokens are never exposed to the user agent, preventing interception. The flow requires the client to interact with the resource owner's user agent (typically a web browser) to complete authentication.

Authorization Code Grant Flow

The OAuth 2.0 Authorization Code Grant flow in EmpowerID:

Flow Steps

  1. Initiate Authorization Request - Direct the user agent to the Authorization endpoint (https://<EID Server>/oauth/v2/ui/authorize) with required parameters:

    • response_type: Set to code for authorization code flow
    • client_id: Client application identifier
    • scope: Space-separated list of permissions (e.g., openid)
    • redirect_uri: Callback URL for post-authentication redirect
    • Optional: state (CSRF prevention) and nonce (replay attack mitigation)
  2. User Authentication - The resource owner submits credentials via the authorization server's login form. Authentication methods include username/password, external identity providers, or multi-factor authentication.

  3. Authorization Code Issued - The authorization server redirects to the redirect_uri with an authorization code and optional id_token in the query parameters.

  4. Token Request - Exchange the authorization code for tokens via a back-channel request to the Token endpoint (https://<EID Server>/oauth/v2/token) with:

    • grant_type: Set to authorization_code
    • client_id: Client application identifier
    • client_secret: Client application secret
    • code: Authorization code from Step 3
  5. Token Response - After validating credentials, the authorization code, and the redirect_uri, the authorization server issues an access token and refresh token.

Authorization Code Grant

  1. Send authorization request to https://<EID Server>/oauth/v2/ui/authorize

    https://<EID Server>/oauth/v2/ui/authorize
    ?client_id=xxxxxxxxxxxxxxxxxx
    &redirect_uri=https%3A%2F%2Ftestoauthapp.com%2FcallbackUrl
    &response_type=code
    &scope=openid
    &state=xxxxxxxxxxxxxxxxxx
    &nonce=xxxxxxxxxxxxxxxxxx
    Request ParameterRequired/OptionalDescription
    response_typerequiredSet to code for authorization code flow. Use code id_token for OpenID Connect.
    client_idrequiredEmpowerID OAuth application client identifier
    redirect_urirequiredCallback URL registered in the EmpowerID OAuth application
    scoperequiredSpace-separated permission list. Include openid for OpenID Connect.
    stateoptionalRandom string for session maintenance and CSRF prevention
    nonceoptionalRandom string for request identification
  2. Authenticate using username/password or an external identity provider.

  3. Authorization server redirects to redirect_uri with response parameters:

    https://testoauthapp.com/callbackUrl
    ?state=xxxxxxxxxxxxxxxxxx
    &code=xxxxxxxxxxxxxxxxxx
    &id_token=xxxxxxxxxxxxxxxxxx
    Response ParameterDescription
    stateSession value from client request
    codeAuthorization code from authorization server
    id_tokenIdentity token (OpenID Connect flow only)
  4. Exchange code for access token at https://<EID Server>/oauth/v2/token

    https://<EID Server>/oauth/v2/token
    ?client_id={The Client ID of the OAuth app you registered in EmpowerID}
    &client_secret={The Client Secret of the OAuth app you registered in EmpowerID}
    &grant_type=authorization_code
    &code=xxxxxxxxxxxxxxxxxx
    Request ParameterRequired/OptionalDescription
    grant_typerequiredSet to authorization_code
    client_idrequiredEmpowerID OAuth application client identifier
    client_secretrequiredEmpowerID OAuth application client secret
    coderequiredAuthorization code from authorization server
  5. Token response:

    {
    "access_token": "xxxxxxxxxxxxxxxxxxxxxx",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "xxxxxxxxxxxxxxxxxxxxxx",
    "id_token": "xxxxxxxxxxxxxxxxxxxxxx",
    "id": "xxxxxxxxxxxxxxxxxxxxxx"
    }

Authorization Code Grant using .NET Client Library

  1. Initialize ClientSettings and AuthorizationCodeGrant:

    var clientSettings = new ClientSettings(
    "client_id",
    "client_secret",
    "redirect_uri",
    "https://<EID Server>/oauth/v2/token",
    "https://<EID Server>/oauth/v2/ui/authorize",
    "https://<EID Server>/oauth/v2/tokeninfo",
    "https://<EID Server>/oauth/v2/userinfo");

    var handler = new AuthorizationCodeGrant(clientSettings);
  2. Build authorization request parameters using BuildAuthorizationRequestPacket():

    //Generate random nonce and state
    var nonce = Guid.NewGuid().ToString("N");
    var state = Guid.NewGuid().ToString("N");

    //Build parameters for "code" flow
    var parameters = handler.BuildAuthorizationRequestPacket
    (ParameterFormat.FormUrlEncoded, state, null, nonce, null);

    //Build parameters for "code id_token" flow
    var responseTypes = new List<ResponseType> { ResponseType.id_token };
    var parameters = handler.BuildAuthorizationRequestPacket
    (ParameterFormat.FormUrlEncoded, state, "openid", nonce, responseTypes);

    //Generate redirect URL
    var redirectUrl = string.Format("{0}?{1}", clientSettings.AuthorizeUrl, parameters);
    1. In the callback method, extract code and state, then request tokens:
    public ActionResult AuthorizationCodeGrantResponse(AuthorizationResponseModel model)
    {
    AuthorizationResponseModel authorizationResponseModel = new AuthorizationResponseModel() {Code = "xxxxxxx", State = state};
    AccessTokenResponseModel tokenResponseModel = null;
    try
    {
    tokenResponseModel = handler.GetAccessToken<AccessTokenResponseModel>(
    RequestMethod.POST,
    ParameterFormat.FormUrlEncoded,
    authorizationResponseModel,
    false);
    }
    catch { //Handle error }
    }

Authorization Code Grant with PKCE (Proof Key for Code Exchange)

  1. Send authorization request to https://<EID Server>/oauth/v2/ui/authorize

    https://<EID Server>/oauth/v2/ui/authorize
    ?client_id=xxxxxxxxxxxxxxxxxx
    &redirect_uri=https%3A%2F%2Ftestoauthapp.com%2FcallbackUrl
    &response_type=code
    &state=xxxxxxxxxxxxxxxxxx
    &nonce=xxxxxxxxxxxxxxxxxx
    &scope=openid
    &code_challenge=xxxxxxxxxxxxxxxxxx
    &code_challenge_method=S256
    Request ParameterRequired/OptionalDescription
    response_typerequiredSet to code for authorization code flow. Use code id_token for OpenID Connect.
    client_idrequiredEmpowerID OAuth application client identifier
    redirect_urirequiredCallback URL registered in the EmpowerID OAuth application
    scoperequiredSpace-separated permission list. Include openid for OpenID Connect.
    code_challenge_methodrecommendedTransformation method: plain or S256. Defaults to plain.
    code_challengerequiredDerived from code_verifier:

    - plain: code_challenge = code_verifier
    - S256: code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

    See PKCE RFC for code verifier generation.
    stateoptionalRandom string for session maintenance and CSRF prevention
    nonceoptionalRandom string for request identification
  2. Authenticate using username/password or an external identity provider.

  3. Authorization server redirects to redirect_uri with response parameters:

    https://testoauthapp.com/callbackUrl
    ?state=xxxxxxxxxxxxxxxxxx
    &code=xxxxxxxxxxxxxxxxxx
    &id_token=xxxxxxxxxxxxxxxxxx
    Response ParameterDescription
    stateSession value from client request
    codeAuthorization code from authorization server
    id_tokenIdentity token (OpenID Connect flow only)
  4. Exchange code for access token at https://<EID Server>/oauth/v2/token

    https://<EID Server>/oauth/v2/token
    ?client_id={The Client ID of the OAuth app you registered in EmpowerID}
    &client_secret={The Client Secret of the OAuth app you registered in EmpowerID}
    &grant_type=authorization_code
    &code=xxxxxxxxxxxxxxxxxx
    &code_verifier=xxxxxxxxxxxxxxxxxx
    Request ParameterRequired/OptionalDescription
    grant_typerequiredSet to authorization_code
    client_idrequiredEmpowerID OAuth application client identifier
    client_secretrequiredEmpowerID OAuth application client secret
    coderequiredAuthorization code from authorization server
    code_verifierrequiredCode verifier from initial authorization request
  5. Token response:

    {
    "access_token": "xxxxxxxxxxxxxxxxxxxxxx",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "xxxxxxxxxxxxxxxxxxxxxx",
    "id_token": "xxxxxxxxxxxxxxxxxxxxxx",
    "id": "xxxxxxxxxxxxxxxxxxxxxx"
    }

Authorization Code Grant with PKCE using .NET Client Library

  1. Initialize ClientSettings and AuthorizationCodeGrant:

    var clientSettings = new ClientSettings(
    "client_id",
    "client_secret",
    "redirect_uri",
    "https://<EID Server>/oauth/v2/token",
    "https://<EID Server>/oauth/v2/ui/authorize",
    "https://<EID Server>/oauth/v2/tokeninfo",
    "https://<EID Server>/oauth/v2/userinfo");

    var handler = new AuthorizationCodeGrant(clientSettings);
  2. Build authorization request with PKCE using BuildAuthorizationRequestPacketWithPKCE():

    //Generate random nonce and state
    var nonce = Guid.NewGuid().ToString("N");
    var state = Guid.NewGuid().ToString("N");

    //Generate code_verifier
    var unreservedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-_`";
    Random random = new Random();
    var code_verifier = new string(Enumerable.Repeat(unreservedChars, 43).Select(s => s[random.Next(s.Length)]).ToArray());

    //Store code_verifier (e.g., in cookie)
    CookieHelper.SetCookieData("OAuthCodeVerifier", code_verifier);

    //Generate code_challenge (plain method)
    //var code_challenge = code_verifier;
    //var code_challenge_method = "plain";

    //Generate code_challenge (S256 method)
    var bytes = new SHA256CryptoServiceProvider().ComputeHash(Encoding.ASCII.GetBytes(code_verifier));
    var code_challenge = Convert.ToBase64String(bytes).Split('=')[0].Replace('+', '-').Replace('/', '_');
    var code_challenge_method = "S256";

    //Build parameters for "code" flow
    var parameters = handler.BuildAuthorizationRequestPacketWithPKCE
    (ParameterFormat.FormUrlEncoded, state, null, nonce, code_challenge, code_challenge_method, null);

    //Build parameters for "code id_token" flow
    //var responseTypes = new List<ResponseType> { ResponseType.id_token };
    //var parameters = handler.BuildAuthorizationRequestPacketWithPKCE
    //(ParameterFormat.FormUrlEncoded, state, "openid", nonce, code_challenge, code_challenge_method, responseTypes);

    //Generate redirect URL
    var redirectUrl = string.Format("{0}?{1}", clientSettings.AuthorizeUrl, parameters);
  3. In the callback method, extract code and state, retrieve code_verifier, then exchange for tokens:

    public ActionResult AuthorizationCodeGrantWithPKCE(AuthorizationCodeGrantViewModel model) 
    {
    AuthorizationResponseModel authorizationResponseModel = new AuthorizationResponseModel() {Code = "xxxxxxx", State = state};

    //Retrieve stored code_verifier
    var code_verifier = CookieHelper.GetCookieData("OAuthCodeVerifier");

    var additionalParams = new Dictionary<string, string>();
    additionalParams["code_verifier"] = code_verifier;

    AccessTokenResponseModel tokenResponseModel = null;
    try
    {
    tokenResponseModel = handler.GetAccessToken<AccessTokenResponseModel>(
    RequestMethod.POST,
    ParameterFormat.FormUrlEncoded,
    authorizationResponseModel,
    false,
    null,
    additionalParams);
    }
    catch { //Handle error }
    }